@rouvanpm/rouva 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ console.log(response.choices[0].message.content)
24
24
 
25
25
  ## Provider agnostic
26
26
 
27
- Rouva works with all connected providers — Anthropic, OpenAI, Gemini, DeepSeek, Mistral, Moonshot, xAI, Z.ai and Alibaba Qwen. You can request a specific model, force a specific provider, or omit both and let Rouva route to the cheapest capable model automatically.
27
+ Rouva works with all connected providers — Anthropic, OpenAI, Gemini, DeepSeek, Mistral, Moonshot, xAI, Z.ai, Alibaba Qwen and MiniMax. You can request a specific model, force a specific provider, or omit both and let Rouva route to the cheapest capable model automatically.
28
28
 
29
29
  ```typescript
30
30
  // Request a specific model
@@ -98,14 +98,15 @@ const res = await rouva.chat.completions.create({
98
98
  })
99
99
  ```
100
100
 
101
- - **`temperature`** — sampling temperature between 0 and 1. The gateway omits it for models that only accept their default: OpenAI reasoning models (gpt-5 / gpt-6 families) and the Claude models that reject it (Opus 4.7 and newer, Sonnet 5 and newer, Fable).
101
+ - **`temperature`** — sampling temperature between 0 and 1. The gateway omits it for models that only accept their default: OpenAI reasoning models (gpt-5 / gpt-6 families) and the Claude models that reject it (Opus 4.7 and newer, Sonnet 5 and newer, Haiku 5.5, Fable), and models whose sampling is fixed (Kimi K3 / K3.1 Pro, MiniMax).
102
102
  - **`max_tokens`** / **`max_completion_tokens`** — either name works. Values below 1024 also steer auto-routing away from reasoning models, which would otherwise spend the whole budget on hidden reasoning tokens.
103
103
  - **`top_p`** — nucleus sampling; `top_p: 1` is treated as omitted. OpenAI reasoning models don't support it: routing avoids them when it's set, and pinning one returns a 400. The gateway omits it for the Claude models that reject it (as for `temperature`).
104
104
  - **`stop`** — a string or up to 4 stop sequences (Anthropic receives them as `stop_sequences`). OpenAI and xAI reasoning models (e.g. gpt-5, grok-4.5 / 4.6 / 4.7) reject it: routing avoids them when it's set, and pinning one returns a 400.
105
105
  - **`metadata`** — up to 10 string key-value pairs (keys up to 64 characters, values up to 256, no null bytes) stored with the request's usage record; not sent to the provider.
106
+ - **`service_tier`** — `'default'` (or Anthropic's `'standard_only'`) asks the provider for its standard tier; `'auto'`, the same as leaving it out, uses your provider account's own setting. Rouva bills standard prices, so other tiers (`flex`, `priority`, `scale`) are a 400.
106
107
  - **`seed`** — best-effort deterministic sampling. Only OpenAI honors it, so it requires an OpenAI `model` and pins the request to that exact model (no routing, no fallbacks).
107
108
  - **`response_format`** — JSON mode or a JSON schema; see [Structured output](#structured-output).
108
- - **`reasoning_effort`** — `'none'` … `'xhigh'`, or `'max'` for Claude. Which values a model takes depends on the model; routing only picks one that takes yours; a listed OpenAI or Claude model you name that doesn't gets a 400, and other providers' models get the value as sent. On gpt-6-luna / gpt-6-sol, `'none'` turns reasoning off. See [the docs](https://rouva.io/docs#reasoning-effort).
109
+ - **`reasoning_effort`** — `'none'` … `'xhigh'`, or `'max'` for Claude. Which values a model takes depends on the model; routing only picks one that takes yours; a listed OpenAI or Claude model you name that doesn't gets a 400, and other providers' models get the value as sent. On gpt-6-luna / gpt-6-sol / gpt-6.1-terra, `'none'` turns reasoning off. See [the docs](https://rouva.io/docs#reasoning-effort).
109
110
  - **`parallel_tool_calls`** — with `tools`: `false` allows at most one tool call per turn (Claude included).
110
111
 
111
112
  Unsupported OpenAI options (`logit_bias`, `logprobs`, `n > 1`, the legacy `functions`/`function_call` fields, …) are rejected by the gateway with an explicit 400 rather than silently ignored.
@@ -130,7 +131,7 @@ Non-tools requests on `/v1` honor the named model exactly unless the workspace o
130
131
 
131
132
  ## Tool use
132
133
 
133
- Tools are forwarded to your target provider verbatim — define them in the **provider's own format** (OpenAI `{ type: "function", function: {...} }` or Anthropic `{ name, description, input_schema }`) and pin the matching `model`. Tool schemas are provider-specific, so `model` is required and the gateway returns a 400 without it. `gpt-6.1-sol` and `gpt-5.6-*` take tools only through OpenAI's Responses API: the gateway uses it for you and converts both ways, so you still send and receive Chat Completions (`seed`, `stop` and a `max_tokens` below 16 are a 400 there). `rouva.run()` still refuses these models.
134
+ Tools are forwarded to your target provider verbatim — define them in the **provider's own format** (OpenAI `{ type: "function", function: {...} }` or Anthropic `{ name, description, input_schema }`) and pin the matching `model`. Tool schemas are provider-specific, so `model` is required and the gateway returns a 400 without it. `gpt-6.1-sol`, `gpt-6-astra` and `gpt-5.6-*` take tools only through OpenAI's Responses API: the gateway uses it for you and converts both ways, so you still send and receive Chat Completions (`seed`, `stop` and a `max_tokens` below 16 are a 400 there). `rouva.run()` still refuses these models.
134
135
 
135
136
  A tools request only ever moves to another model of the **same provider**: an account routing override for the task (when it targets the same provider), or — on the `/v1` endpoint with Intelligent Routing enabled — the cheapest capable model within that provider, using the named `model` as a cost ceiling (see [OpenAI-compatible endpoint](#openai-compatible-endpoint)). Otherwise the named model is honored exactly.
136
137
 
@@ -258,6 +259,8 @@ Every turn is logged as a usage snapshot in the Rouva dashboard under the shared
258
259
  | `max_tokens` | `number` | | Max tokens per turn (default: 4096) |
259
260
  | `temperature` | `number` | | Sampling temperature 0–1 |
260
261
  | `session_budget_usd` | `number` | | Hard USD cap across all turns |
262
+ | `metadata` | `Record<string, string>` | | Your labels (e.g. `customer_id`), stored with every turn's usage record |
263
+ | `service_tier` | `ServiceTier` | | `'default'` / `'standard_only'` for the standard tier, or `'auto'` |
261
264
 
262
265
  ### Result shape
263
266
 
@@ -407,7 +410,7 @@ try {
407
410
  await rouva.chat.completions.create({ messages })
408
411
  } catch (e) {
409
412
  if (e instanceof RouvaError && e.status === 429) {
410
- console.log(e.refusal) // 'key_cap' | 'member_cap' | 'rate' | … — Rouva refused before calling the provider
413
+ console.log(e.refusal) // 'key_cap' | 'plan_limit' | 'rate' | … — Rouva refused before calling the provider
411
414
  console.log(e.retryAfter) // seconds, from Retry-After
412
415
  console.log(e.error) // the gateway's message
413
416
  console.log(e.requestId) // when the request was recorded — rouva.requests.get(e.requestId)
@@ -415,7 +418,7 @@ try {
415
418
  }
416
419
  ```
417
420
 
418
- `refusal` (header `X-Rouva-Refusal`) names why Rouva itself refused the request before contacting the provider, when the gateway marks it: a monthly spend cap would be exceeded (`key_cap`, `member_cap`), the rate limit (`rate`), for spend-capped keys a model with no known price (`unpriced`) or input or a model whose cost can't be bounded (`unbounded`), or — a `504` — the request ran out of its time budget before the provider was called (`deadline`; nothing was sent, so it's safe to retry, and `retryAfter` is set). Every Rouva refusal is marked, so a `429` or `504` without `refusal` came from the provider, not from Rouva — with one exception: `rouva.run()` returns an unmarked `504` "Run deadline exceeded before completion" when the run runs out of time, because earlier turns were already billed and their tool handlers ran; check what completed before retrying it. Every call also takes `{ signal }` as a second argument to abort it.
421
+ `refusal` (header `X-Rouva-Refusal`) names why Rouva itself refused the request before contacting the provider, when the gateway marks it: a monthly spend cap would be exceeded (`key_cap`, `member_cap`, or `customer_cap` for a `metadata.customer_id` customer), the account is on the Free plan and has used its requests for the month (`plan_limit`, a `429`; `retryAfter` runs to the 1st of next month, UTC, or upgrade the plan), the rate limit (`rate`), for spend-capped keys a model with no known price (`unpriced`) or input or a model whose cost can't be bounded (`unbounded`), or — a `504` — the request ran out of its time budget before the provider was called (`deadline`; nothing was sent, so it's safe to retry, and `retryAfter` is set). Every Rouva refusal is marked, so a `429` or `504` without `refusal` came from the provider, not from Rouva — with one exception: `rouva.run()` returns an unmarked `504` "Run deadline exceeded before completion" when the run runs out of time, because earlier turns were already billed and their tool handlers ran; check what completed before retrying it. Every call also takes `{ signal }` as a second argument to abort it.
419
422
 
420
423
  ## Getting your API key
421
424
 
package/dist/index.d.mts CHANGED
@@ -50,9 +50,17 @@ interface ContentBlockMessage {
50
50
  * valid when `tools` is set on the request.
51
51
  */
52
52
  type ChatMessage = Message | AssistantToolCallMessage | ToolResultMessage | ContentBlockMessage;
53
- type RouvaProvider = 'anthropic' | 'openai' | 'gemini' | 'deepseek' | 'mistral' | 'moonshot' | 'xai' | 'zai' | 'alibaba' | (string & {});
53
+ /** `service_tier` values the gateway serves (see `ChatCompletionParams.service_tier`). */
54
+ type ServiceTier = 'auto' | 'default' | 'standard_only';
54
55
  /**
55
- * Supported models across all providers (the gateway's list as of SDK 0.3.0).
56
+ * Why Rouva itself refused a request (`RouvaError.refusal`, header
57
+ * `X-Rouva-Refusal`). See `RouvaError.refusal` for each kind. Other strings
58
+ * are allowed so a newer gateway's kinds still type-check.
59
+ */
60
+ type RouvaRefusal = 'key_cap' | 'member_cap' | 'customer_cap' | 'plan_limit' | 'rate' | 'unpriced' | 'unbounded' | 'deadline' | (string & {});
61
+ type RouvaProvider = 'anthropic' | 'openai' | 'gemini' | 'deepseek' | 'mistral' | 'moonshot' | 'xai' | 'zai' | 'alibaba' | 'minimax' | (string & {});
62
+ /**
63
+ * Supported models across all providers (the gateway's list as of SDK 0.5.2).
56
64
  * Omit `model` entirely to let Rouva route to the cheapest capable model automatically.
57
65
  *
58
66
  * Other IDs are accepted by the type for forward compatibility. On
@@ -64,7 +72,7 @@ type RouvaProvider = 'anthropic' | 'openai' | 'gemini' | 'deepseek' | 'mistral'
64
72
  *
65
73
  * `'gpt-5.6'` is a deprecated alias the gateway maps to `'gpt-5.6-sol'`.
66
74
  */
67
- type RouvaModel = 'claude-fable-5-1' | 'claude-fable-5' | 'claude-opus-5-5' | 'claude-opus-5' | 'claude-opus-4-8' | 'claude-opus-4-7' | 'claude-opus-4-6' | 'claude-sonnet-5-5' | 'claude-sonnet-5' | 'claude-sonnet-4-6' | 'claude-haiku-4-5-20251001' | 'gpt-6.1-sol' | 'gpt-6-sol' | 'gpt-6-luna' | 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5.6' | 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5-mini' | 'gpt-5-nano' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4o' | 'gpt-4o-mini' | 'gemini-3.8-flash' | 'gemini-3.7-flash' | 'gemini-3.6-flash' | 'gemini-3.5-flash-lite' | 'gemini-2.5-pro' | 'gemini-2.5-flash' | 'deepseek-flash' | 'deepseek-flash-think' | 'deepseek-v4-pro' | 'mistral-large-latest' | 'mistral-small-latest' | 'kimi-k3' | 'kimi-k2.6' | 'grok-4.7' | 'grok-4.6' | 'grok-4.5' | 'grok-4.3' | 'grok-4.20-0309-reasoning' | 'glm-5.3' | 'glm-5.2' | 'glm-4.7-flash' | 'qwen3.8-omni-flash' | 'qwen3.8-flash' | 'qwen3.7-plus' | 'qwen-max' | 'qwen-plus' | 'qwen-flash' | (string & {});
75
+ type RouvaModel = 'claude-fable-5-1' | 'claude-fable-5' | 'claude-opus-5-5' | 'claude-opus-5' | 'claude-opus-4-8' | 'claude-opus-4-7' | 'claude-opus-4-6' | 'claude-sonnet-5-5' | 'claude-sonnet-5' | 'claude-sonnet-4-6' | 'claude-haiku-5-5' | 'claude-haiku-4-5-20251001' | 'gpt-6-astra' | 'gpt-6.1-sol' | 'gpt-6.1-terra' | 'gpt-6-sol' | 'gpt-6-luna' | 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5.6' | 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5-mini' | 'gpt-5-nano' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4o' | 'gpt-4o-mini' | 'gemini-4-argon' | 'gemini-3.8-flash' | 'gemini-3.7-flash' | 'gemini-3.6-flash' | 'gemini-3.5-flash-lite' | 'gemini-2.5-pro' | 'gemini-2.5-flash' | 'deepseek-flash' | 'deepseek-flash-think' | 'deepseek-v4-pro' | 'mistral-large-4' | 'mistral-large-latest' | 'mistral-small-latest' | 'kimi-k3.1-pro' | 'kimi-k3' | 'kimi-k2.6' | 'grok-4.7' | 'grok-4.6' | 'grok-4.5' | 'grok-4.3' | 'grok-4.20-0309-reasoning' | 'glm-5.3' | 'glm-5.2' | 'glm-4.7-flash' | 'qwen3.8-omni-flash' | 'qwen3.8-flash' | 'qwen3.7-plus' | 'qwen-max' | 'qwen-plus' | 'qwen-flash' | 'MiniMax-M3.1-Flash' | 'MiniMax-M3' | (string & {});
68
76
  /** Anthropic-style text block — the array form of the `system` param */
69
77
  interface SystemTextBlock {
70
78
  type: 'text';
@@ -104,11 +112,21 @@ interface ChatCompletionParams {
104
112
  * characters, values up to 256 characters, no null bytes.
105
113
  */
106
114
  metadata?: Record<string, string>;
115
+ /**
116
+ * Which provider service tier to use. Rouva bills standard prices, so only
117
+ * the standard tier is served: `'default'` (OpenAI's name) or
118
+ * `'standard_only'` (Anthropic's) asks for it — sent in the dialect of
119
+ * whichever provider the request reaches; `'auto'` (the same as leaving it
120
+ * out) uses your provider account's own setting. Any other tier (`flex`,
121
+ * `priority`, `scale`, …) is a 400.
122
+ */
123
+ service_tier?: ServiceTier;
107
124
  /**
108
125
  * Sampling temperature 0–1.
109
126
  * The gateway omits it for models that only accept their default: OpenAI
110
127
  * reasoning models (gpt-5 / gpt-6 families) and the Claude models that reject
111
- * it (Opus 4.7 and newer, Sonnet 5 and newer, Fable).
128
+ * it (Opus 4.7 and newer, Sonnet 5 and newer, Haiku 5.5, Fable), and for
129
+ * models whose sampling is fixed (Kimi K3 / K3.1 Pro, MiniMax).
112
130
  */
113
131
  temperature?: number;
114
132
  /**
@@ -116,7 +134,8 @@ interface ChatCompletionParams {
116
134
  * default) is treated as omitted. OpenAI reasoning models (gpt-5 / gpt-6
117
135
  * families, o-series) don't support it: routing avoids them when top_p is
118
136
  * set, and pinning one returns a 400. The gateway omits it for the Claude
119
- * models that reject it (Opus 4.7 and newer, Sonnet 5 and newer, Fable).
137
+ * models that reject it (Opus 4.7 and newer, Sonnet 5 and newer, Haiku 5.5, Fable),
138
+ * and for models whose sampling is fixed (Kimi K3 / K3.1 Pro, MiniMax).
120
139
  */
121
140
  top_p?: number;
122
141
  /**
@@ -147,11 +166,11 @@ interface ChatCompletionParams {
147
166
  * How hard a reasoning model thinks (gateway support since 2026-10-21).
148
167
  * OpenAI models take it as is; Claude gets it as `output_config.effort`.
149
168
  * Values depend on the model: gpt-5 / -mini / -nano take minimal–high;
150
- * gpt-5.4-mini, gpt-5.6-*, gpt-6-luna / -sol take none–xhigh; gpt-6.1-sol
151
- * low–xhigh; Claude Sonnet / Opus 4.6 low, medium, high, max; newer Claude
152
- * models also xhigh; GPT-4 models and Claude Haiku 4.5 don't take it. Routing
169
+ * gpt-5.4-mini, gpt-5.6-*, gpt-6-luna / -sol, gpt-6.1-terra take none–xhigh;
170
+ * gpt-6.1-sol and gpt-6-astra low–xhigh; Claude Sonnet / Opus 4.6 low, medium,
171
+ * high, max; newer Claude models (incl. Haiku 5.5) also xhigh; GPT-4 models and Claude Haiku 4.5 don't take it. Routing
153
172
  * only picks a model that takes the value; a listed OpenAI or Claude model you
154
- * name that doesn't is a 400 (other providers' models get the value as sent). On gpt-6-luna / -sol, `'none'` turns reasoning off (temperature,
173
+ * name that doesn't is a 400 (other providers' models get the value as sent). On gpt-6-luna / -sol and gpt-6.1-terra, `'none'` turns reasoning off (temperature,
155
174
  * top_p and tools then work) and any other value turns it on (top_p is then
156
175
  * a 400; tools are served through OpenAI's Responses API). `rouva.run()`
157
176
  * doesn't accept it.
@@ -176,7 +195,7 @@ interface ChatCompletionParams {
176
195
  * Anthropic `{ name, description, input_schema }`). Requires `model`.
177
196
  * Tool schemas are provider-specific, so a tools request only ever moves to
178
197
  * another model of the SAME provider (a routing override, or cheaper-model
179
- * routing on /v1). gpt-6.1-sol and gpt-5.6-* take tools only through
198
+ * routing on /v1). gpt-6.1-sol, gpt-6-astra and gpt-5.6-* take tools only through
180
199
  * OpenAI's Responses API: the gateway uses it for you and converts both ways
181
200
  * (you still send and receive Chat Completions), and there `seed`, `stop` and
182
201
  * a `max_tokens` below 16 are a 400. `rouva.run()` still refuses these models.
@@ -442,6 +461,23 @@ interface RunParams {
442
461
  * all turns reaches this threshold.
443
462
  */
444
463
  session_budget_usd?: number;
464
+ /**
465
+ * Your own labels for the run, stored with every turn's usage record and
466
+ * not sent to the provider (e.g. `{ customer_id: 'acme' }` for the
467
+ * dashboard's Customers page and per-customer spend caps): up to 10 string
468
+ * key-value pairs, keys up to 64 characters, values up to 256 characters,
469
+ * no null bytes.
470
+ */
471
+ metadata?: Record<string, string>;
472
+ /**
473
+ * Which provider service tier to use. Rouva bills standard prices, so only
474
+ * the standard tier is served: `'default'` (OpenAI's name) or
475
+ * `'standard_only'` (Anthropic's) asks for it — sent in the dialect of
476
+ * whichever provider the request reaches; `'auto'` (the same as leaving it
477
+ * out) uses your provider account's own setting. Any other tier (`flex`,
478
+ * `priority`, `scale`, …) is a 400.
479
+ */
480
+ service_tier?: ServiceTier;
445
481
  }
446
482
  interface RunResult {
447
483
  /** Final model response text after all tool loops complete. */
@@ -585,8 +621,11 @@ declare class RouvaError extends Error {
585
621
  /**
586
622
  * Why Rouva itself refused the request before contacting the provider, when
587
623
  * the gateway marks it (header `X-Rouva-Refusal`): `"key_cap"` /
588
- * `"member_cap"` (a monthly spend cap would be exceeded), `"rate"` (rate
589
- * limit), `"unpriced"` (a capped key can't use a model with no known price),
624
+ * `"member_cap"` / `"customer_cap"` (a monthly spend cap — the key's, the
625
+ * workspace member's, or the `metadata.customer_id` customer's — would be
626
+ * exceeded), `"plan_limit"` (a 429: the account is on the Free plan and has
627
+ * used its requests for the month; `retryAfter` runs to the 1st of next
628
+ * month, UTC — or upgrade the plan), `"rate"` (rate limit), `"unpriced"` (a capped key can't use a model with no known price),
590
629
  * `"unbounded"` (a capped key can't send input, or use a model, whose cost
591
630
  * can't be bounded), `"deadline"` (a 504: the request ran out of its time
592
631
  * budget before the provider was called — nothing was sent, so it's safe to
@@ -596,7 +635,7 @@ declare class RouvaError extends Error {
596
635
  * Rouva's but deliberately unmarked: earlier turns were billed and their
597
636
  * tool handlers ran, so it must not be retried blindly.
598
637
  */
599
- readonly refusal?: string;
638
+ readonly refusal?: RouvaRefusal;
600
639
  /** Seconds to wait before retrying, from `Retry-After`, when present. */
601
640
  readonly retryAfter?: number;
602
641
  /** The gateway's error message (`error` field), when the body is JSON. */
@@ -613,4 +652,4 @@ declare class RouvaError extends Error {
613
652
  constructor(kind: 'Gateway' | 'Run' | 'Request' | 'Explain', status: number, headers: Headers, rawBody: string);
614
653
  }
615
654
 
616
- export { type AssistantToolCallMessage, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionParams, type ChatCompletionUsage, type ChatMessage, type ContentBlockMessage, type ExplainOptions, type FunctionToolCall, type Message, type ReasoningEffort, type RequestOptions, type ResponseFormat, type ResponseMessage, Rouva, RouvaError, type RouvaExplainResult, type RouvaExplainedRefusal, type RouvaExplanation, type RouvaModel, type RouvaOptions, type RouvaProvider, type RouvaRequest, type RouvaRequestStatus, type RouvaResponseMeta, type RouvaRouteReason, type RouvaStream, type RunParams, type RunResult, type SystemTextBlock, type ToolResultMessage };
655
+ export { type AssistantToolCallMessage, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionParams, type ChatCompletionUsage, type ChatMessage, type ContentBlockMessage, type ExplainOptions, type FunctionToolCall, type Message, type ReasoningEffort, type RequestOptions, type ResponseFormat, type ResponseMessage, Rouva, RouvaError, type RouvaExplainResult, type RouvaExplainedRefusal, type RouvaExplanation, type RouvaModel, type RouvaOptions, type RouvaProvider, type RouvaRefusal, type RouvaRequest, type RouvaRequestStatus, type RouvaResponseMeta, type RouvaRouteReason, type RouvaStream, type RunParams, type RunResult, type ServiceTier, type SystemTextBlock, type ToolResultMessage };
package/dist/index.d.ts CHANGED
@@ -50,9 +50,17 @@ interface ContentBlockMessage {
50
50
  * valid when `tools` is set on the request.
51
51
  */
52
52
  type ChatMessage = Message | AssistantToolCallMessage | ToolResultMessage | ContentBlockMessage;
53
- type RouvaProvider = 'anthropic' | 'openai' | 'gemini' | 'deepseek' | 'mistral' | 'moonshot' | 'xai' | 'zai' | 'alibaba' | (string & {});
53
+ /** `service_tier` values the gateway serves (see `ChatCompletionParams.service_tier`). */
54
+ type ServiceTier = 'auto' | 'default' | 'standard_only';
54
55
  /**
55
- * Supported models across all providers (the gateway's list as of SDK 0.3.0).
56
+ * Why Rouva itself refused a request (`RouvaError.refusal`, header
57
+ * `X-Rouva-Refusal`). See `RouvaError.refusal` for each kind. Other strings
58
+ * are allowed so a newer gateway's kinds still type-check.
59
+ */
60
+ type RouvaRefusal = 'key_cap' | 'member_cap' | 'customer_cap' | 'plan_limit' | 'rate' | 'unpriced' | 'unbounded' | 'deadline' | (string & {});
61
+ type RouvaProvider = 'anthropic' | 'openai' | 'gemini' | 'deepseek' | 'mistral' | 'moonshot' | 'xai' | 'zai' | 'alibaba' | 'minimax' | (string & {});
62
+ /**
63
+ * Supported models across all providers (the gateway's list as of SDK 0.5.2).
56
64
  * Omit `model` entirely to let Rouva route to the cheapest capable model automatically.
57
65
  *
58
66
  * Other IDs are accepted by the type for forward compatibility. On
@@ -64,7 +72,7 @@ type RouvaProvider = 'anthropic' | 'openai' | 'gemini' | 'deepseek' | 'mistral'
64
72
  *
65
73
  * `'gpt-5.6'` is a deprecated alias the gateway maps to `'gpt-5.6-sol'`.
66
74
  */
67
- type RouvaModel = 'claude-fable-5-1' | 'claude-fable-5' | 'claude-opus-5-5' | 'claude-opus-5' | 'claude-opus-4-8' | 'claude-opus-4-7' | 'claude-opus-4-6' | 'claude-sonnet-5-5' | 'claude-sonnet-5' | 'claude-sonnet-4-6' | 'claude-haiku-4-5-20251001' | 'gpt-6.1-sol' | 'gpt-6-sol' | 'gpt-6-luna' | 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5.6' | 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5-mini' | 'gpt-5-nano' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4o' | 'gpt-4o-mini' | 'gemini-3.8-flash' | 'gemini-3.7-flash' | 'gemini-3.6-flash' | 'gemini-3.5-flash-lite' | 'gemini-2.5-pro' | 'gemini-2.5-flash' | 'deepseek-flash' | 'deepseek-flash-think' | 'deepseek-v4-pro' | 'mistral-large-latest' | 'mistral-small-latest' | 'kimi-k3' | 'kimi-k2.6' | 'grok-4.7' | 'grok-4.6' | 'grok-4.5' | 'grok-4.3' | 'grok-4.20-0309-reasoning' | 'glm-5.3' | 'glm-5.2' | 'glm-4.7-flash' | 'qwen3.8-omni-flash' | 'qwen3.8-flash' | 'qwen3.7-plus' | 'qwen-max' | 'qwen-plus' | 'qwen-flash' | (string & {});
75
+ type RouvaModel = 'claude-fable-5-1' | 'claude-fable-5' | 'claude-opus-5-5' | 'claude-opus-5' | 'claude-opus-4-8' | 'claude-opus-4-7' | 'claude-opus-4-6' | 'claude-sonnet-5-5' | 'claude-sonnet-5' | 'claude-sonnet-4-6' | 'claude-haiku-5-5' | 'claude-haiku-4-5-20251001' | 'gpt-6-astra' | 'gpt-6.1-sol' | 'gpt-6.1-terra' | 'gpt-6-sol' | 'gpt-6-luna' | 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5.6' | 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5-mini' | 'gpt-5-nano' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4o' | 'gpt-4o-mini' | 'gemini-4-argon' | 'gemini-3.8-flash' | 'gemini-3.7-flash' | 'gemini-3.6-flash' | 'gemini-3.5-flash-lite' | 'gemini-2.5-pro' | 'gemini-2.5-flash' | 'deepseek-flash' | 'deepseek-flash-think' | 'deepseek-v4-pro' | 'mistral-large-4' | 'mistral-large-latest' | 'mistral-small-latest' | 'kimi-k3.1-pro' | 'kimi-k3' | 'kimi-k2.6' | 'grok-4.7' | 'grok-4.6' | 'grok-4.5' | 'grok-4.3' | 'grok-4.20-0309-reasoning' | 'glm-5.3' | 'glm-5.2' | 'glm-4.7-flash' | 'qwen3.8-omni-flash' | 'qwen3.8-flash' | 'qwen3.7-plus' | 'qwen-max' | 'qwen-plus' | 'qwen-flash' | 'MiniMax-M3.1-Flash' | 'MiniMax-M3' | (string & {});
68
76
  /** Anthropic-style text block — the array form of the `system` param */
69
77
  interface SystemTextBlock {
70
78
  type: 'text';
@@ -104,11 +112,21 @@ interface ChatCompletionParams {
104
112
  * characters, values up to 256 characters, no null bytes.
105
113
  */
106
114
  metadata?: Record<string, string>;
115
+ /**
116
+ * Which provider service tier to use. Rouva bills standard prices, so only
117
+ * the standard tier is served: `'default'` (OpenAI's name) or
118
+ * `'standard_only'` (Anthropic's) asks for it — sent in the dialect of
119
+ * whichever provider the request reaches; `'auto'` (the same as leaving it
120
+ * out) uses your provider account's own setting. Any other tier (`flex`,
121
+ * `priority`, `scale`, …) is a 400.
122
+ */
123
+ service_tier?: ServiceTier;
107
124
  /**
108
125
  * Sampling temperature 0–1.
109
126
  * The gateway omits it for models that only accept their default: OpenAI
110
127
  * reasoning models (gpt-5 / gpt-6 families) and the Claude models that reject
111
- * it (Opus 4.7 and newer, Sonnet 5 and newer, Fable).
128
+ * it (Opus 4.7 and newer, Sonnet 5 and newer, Haiku 5.5, Fable), and for
129
+ * models whose sampling is fixed (Kimi K3 / K3.1 Pro, MiniMax).
112
130
  */
113
131
  temperature?: number;
114
132
  /**
@@ -116,7 +134,8 @@ interface ChatCompletionParams {
116
134
  * default) is treated as omitted. OpenAI reasoning models (gpt-5 / gpt-6
117
135
  * families, o-series) don't support it: routing avoids them when top_p is
118
136
  * set, and pinning one returns a 400. The gateway omits it for the Claude
119
- * models that reject it (Opus 4.7 and newer, Sonnet 5 and newer, Fable).
137
+ * models that reject it (Opus 4.7 and newer, Sonnet 5 and newer, Haiku 5.5, Fable),
138
+ * and for models whose sampling is fixed (Kimi K3 / K3.1 Pro, MiniMax).
120
139
  */
121
140
  top_p?: number;
122
141
  /**
@@ -147,11 +166,11 @@ interface ChatCompletionParams {
147
166
  * How hard a reasoning model thinks (gateway support since 2026-10-21).
148
167
  * OpenAI models take it as is; Claude gets it as `output_config.effort`.
149
168
  * Values depend on the model: gpt-5 / -mini / -nano take minimal–high;
150
- * gpt-5.4-mini, gpt-5.6-*, gpt-6-luna / -sol take none–xhigh; gpt-6.1-sol
151
- * low–xhigh; Claude Sonnet / Opus 4.6 low, medium, high, max; newer Claude
152
- * models also xhigh; GPT-4 models and Claude Haiku 4.5 don't take it. Routing
169
+ * gpt-5.4-mini, gpt-5.6-*, gpt-6-luna / -sol, gpt-6.1-terra take none–xhigh;
170
+ * gpt-6.1-sol and gpt-6-astra low–xhigh; Claude Sonnet / Opus 4.6 low, medium,
171
+ * high, max; newer Claude models (incl. Haiku 5.5) also xhigh; GPT-4 models and Claude Haiku 4.5 don't take it. Routing
153
172
  * only picks a model that takes the value; a listed OpenAI or Claude model you
154
- * name that doesn't is a 400 (other providers' models get the value as sent). On gpt-6-luna / -sol, `'none'` turns reasoning off (temperature,
173
+ * name that doesn't is a 400 (other providers' models get the value as sent). On gpt-6-luna / -sol and gpt-6.1-terra, `'none'` turns reasoning off (temperature,
155
174
  * top_p and tools then work) and any other value turns it on (top_p is then
156
175
  * a 400; tools are served through OpenAI's Responses API). `rouva.run()`
157
176
  * doesn't accept it.
@@ -176,7 +195,7 @@ interface ChatCompletionParams {
176
195
  * Anthropic `{ name, description, input_schema }`). Requires `model`.
177
196
  * Tool schemas are provider-specific, so a tools request only ever moves to
178
197
  * another model of the SAME provider (a routing override, or cheaper-model
179
- * routing on /v1). gpt-6.1-sol and gpt-5.6-* take tools only through
198
+ * routing on /v1). gpt-6.1-sol, gpt-6-astra and gpt-5.6-* take tools only through
180
199
  * OpenAI's Responses API: the gateway uses it for you and converts both ways
181
200
  * (you still send and receive Chat Completions), and there `seed`, `stop` and
182
201
  * a `max_tokens` below 16 are a 400. `rouva.run()` still refuses these models.
@@ -442,6 +461,23 @@ interface RunParams {
442
461
  * all turns reaches this threshold.
443
462
  */
444
463
  session_budget_usd?: number;
464
+ /**
465
+ * Your own labels for the run, stored with every turn's usage record and
466
+ * not sent to the provider (e.g. `{ customer_id: 'acme' }` for the
467
+ * dashboard's Customers page and per-customer spend caps): up to 10 string
468
+ * key-value pairs, keys up to 64 characters, values up to 256 characters,
469
+ * no null bytes.
470
+ */
471
+ metadata?: Record<string, string>;
472
+ /**
473
+ * Which provider service tier to use. Rouva bills standard prices, so only
474
+ * the standard tier is served: `'default'` (OpenAI's name) or
475
+ * `'standard_only'` (Anthropic's) asks for it — sent in the dialect of
476
+ * whichever provider the request reaches; `'auto'` (the same as leaving it
477
+ * out) uses your provider account's own setting. Any other tier (`flex`,
478
+ * `priority`, `scale`, …) is a 400.
479
+ */
480
+ service_tier?: ServiceTier;
445
481
  }
446
482
  interface RunResult {
447
483
  /** Final model response text after all tool loops complete. */
@@ -585,8 +621,11 @@ declare class RouvaError extends Error {
585
621
  /**
586
622
  * Why Rouva itself refused the request before contacting the provider, when
587
623
  * the gateway marks it (header `X-Rouva-Refusal`): `"key_cap"` /
588
- * `"member_cap"` (a monthly spend cap would be exceeded), `"rate"` (rate
589
- * limit), `"unpriced"` (a capped key can't use a model with no known price),
624
+ * `"member_cap"` / `"customer_cap"` (a monthly spend cap — the key's, the
625
+ * workspace member's, or the `metadata.customer_id` customer's — would be
626
+ * exceeded), `"plan_limit"` (a 429: the account is on the Free plan and has
627
+ * used its requests for the month; `retryAfter` runs to the 1st of next
628
+ * month, UTC — or upgrade the plan), `"rate"` (rate limit), `"unpriced"` (a capped key can't use a model with no known price),
590
629
  * `"unbounded"` (a capped key can't send input, or use a model, whose cost
591
630
  * can't be bounded), `"deadline"` (a 504: the request ran out of its time
592
631
  * budget before the provider was called — nothing was sent, so it's safe to
@@ -596,7 +635,7 @@ declare class RouvaError extends Error {
596
635
  * Rouva's but deliberately unmarked: earlier turns were billed and their
597
636
  * tool handlers ran, so it must not be retried blindly.
598
637
  */
599
- readonly refusal?: string;
638
+ readonly refusal?: RouvaRefusal;
600
639
  /** Seconds to wait before retrying, from `Retry-After`, when present. */
601
640
  readonly retryAfter?: number;
602
641
  /** The gateway's error message (`error` field), when the body is JSON. */
@@ -613,4 +652,4 @@ declare class RouvaError extends Error {
613
652
  constructor(kind: 'Gateway' | 'Run' | 'Request' | 'Explain', status: number, headers: Headers, rawBody: string);
614
653
  }
615
654
 
616
- export { type AssistantToolCallMessage, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionParams, type ChatCompletionUsage, type ChatMessage, type ContentBlockMessage, type ExplainOptions, type FunctionToolCall, type Message, type ReasoningEffort, type RequestOptions, type ResponseFormat, type ResponseMessage, Rouva, RouvaError, type RouvaExplainResult, type RouvaExplainedRefusal, type RouvaExplanation, type RouvaModel, type RouvaOptions, type RouvaProvider, type RouvaRequest, type RouvaRequestStatus, type RouvaResponseMeta, type RouvaRouteReason, type RouvaStream, type RunParams, type RunResult, type SystemTextBlock, type ToolResultMessage };
655
+ export { type AssistantToolCallMessage, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionParams, type ChatCompletionUsage, type ChatMessage, type ContentBlockMessage, type ExplainOptions, type FunctionToolCall, type Message, type ReasoningEffort, type RequestOptions, type ResponseFormat, type ResponseMessage, Rouva, RouvaError, type RouvaExplainResult, type RouvaExplainedRefusal, type RouvaExplanation, type RouvaModel, type RouvaOptions, type RouvaProvider, type RouvaRefusal, type RouvaRequest, type RouvaRequestStatus, type RouvaResponseMeta, type RouvaRouteReason, type RouvaStream, type RunParams, type RunResult, type ServiceTier, type SystemTextBlock, type ToolResultMessage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rouvanpm/rouva",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Official Node.js SDK for Rouva — managed AI gateway with intelligent routing and spend tracking",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",