flexinference 1.5.1 → 1.5.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.3
4
+
5
+ Relaxes Messages `max_tokens` on the FlexInference side. The SDK no longer requires or
6
+ runtime-validates it before sending a `/messages` request; FlexInference forwards it when
7
+ set and lets Anthropic return its own request error when it is omitted.
8
+
9
+ ## 1.5.2
10
+
11
+ Adds zero-dependency runtime request validation matching the Python SDK: a request is now
12
+ checked for `model` and the per-endpoint required fields before it is sent, with the two SDKs
13
+ held to identical behavior by shared parity fixtures. The generated `Error` type also gains a
14
+ `doc_url` field, so an error now carries a link to its documentation.
15
+
3
16
  ## 1.5.1
4
17
 
5
18
  Small robustness fixes for the transport, no API changes. A non-streaming request that hits
@@ -7,8 +20,8 @@ its total `timeout` now throws a clear timeout error instead of a bare abort tha
7
20
  a caller cancellation. A streamed response flushes its decoder and delivers the final frame
8
21
  even when the stream ends without a trailing blank line, so the last event is never dropped,
9
22
  and the streaming buffer is capped so a stream that never sends a separator cannot grow
10
- without bound. The `start_within` type now matches the runtime rule, so a value the client
11
- would reject at run time no longer type-checks.
23
+ without bound. The `start_within` type now requires the runtime's two-digit duration
24
+ shape, so values like `0h-5m-0s` no longer type-check.
12
25
 
13
26
  ## 1.5.0
14
27
 
@@ -82,11 +95,11 @@ required and aligns its values with OpenAI's `service_tier` vocabulary.
82
95
 
83
96
  ### Breaking changes
84
97
 
85
- - **`start_within` is now required on every request.** It is typed as
86
- `StartWithin = "default" | "priority" | "auto" | \`${number}h-${number}m-${number}s\``,
87
- so omitting it (or passing a value outside those shapes) is a **compile-time** error.
88
- A duration that fits the shape but is malformed or out of range is caught at **runtime**;
89
- plain-JS callers get every check at **runtime** (a thrown `Error` before any network call).
98
+ - **`start_within` is now required on every request.** It is typed as `"default"`,
99
+ `"priority"`, `"auto"`, or a duration shaped like `"00h-05m-00s"`, so omitting it
100
+ (or passing a value outside those shapes) is a **compile-time** error.
101
+ A duration that fits the shape but is malformed or out of range is caught at **runtime**;
102
+ plain-JS callers get every check at **runtime** (a thrown `Error` before any network call).
90
103
  - **Accepted values changed.** `start_within` now takes `"default"`, `"priority"`,
91
104
  `"auto"`, or a duration `"HHh-MMm-SSs"` (5s-10m). The old `"standard"` value is
92
105
  removed; use `"default"` (it maps to the same OpenAI service tier).
package/README.md CHANGED
@@ -34,7 +34,7 @@ FlexInference routes to **OpenAI**, **Google Gemini**, and **Anthropic**. Send t
34
34
 
35
35
  - **OpenAI:** `default` (the standard tier), `priority`, `auto`, and flex on flex-capable models. You reach flex by passing a duration.
36
36
  - **Gemini:** `default` maps to Gemini's standard tier. You also get `priority` and flex on the Gemini flex models (`gemini-3.5-flash`, `gemini-3.1-flash-lite`, `gemini-3.1-pro-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.5-flash-lite`). Gemini has no `auto` tier, so `start_within: "auto"` on a Gemini model returns `400`.
37
- - **Anthropic (Claude):** proxy-only. `default`, `priority`, and `auto` work; there is **no flex tier**, so a duration `start_within` on a `claude-*` model returns `400 flex_unsupported_for_anthropic`. Anthropic requires a token cap, so set `max_output_tokens` (`max_completion_tokens` on Chat, `max_tokens` on Messages) or you get `400 missing_max_tokens`. You keep the unified API and tier control, and draw down your own Anthropic credits.
37
+ - **Anthropic (Claude):** proxy-only. `default`, `priority`, and `auto` work; there is **no flex tier**, so a duration `start_within` on a `claude-*` model returns `400 flex_unsupported_for_anthropic`. Anthropic requires an output-token field upstream. FlexInference forwards `max_output_tokens` (`max_completion_tokens` on Chat, `max_tokens` on Messages) when set and does not synthesize a default, so omitting it returns Anthropic's own request error. You keep the unified API and tier control, and draw down your own Anthropic credits.
38
38
 
39
39
  Add the provider key you'll use (OpenAI, Gemini, and/or Anthropic) in the [dashboard](https://www.flexinference.com/dashboard). Text, streaming, structured outputs, function calling, image input, and web search work across providers (send a Responses `web_search` tool; we map it to Gemini's `google_search`).
40
40
 
@@ -85,7 +85,7 @@ console.log(interactionText(res));
85
85
 
86
86
  ## Messages (Anthropic shape)
87
87
 
88
- Speak Anthropic's Messages shape and reach any model. `max_tokens` is required (Anthropic requires it). `messageText(res)` pulls the assistant text out of the message `content`.
88
+ Speak Anthropic's Messages shape and reach any model. Anthropic requires `max_tokens` upstream. FlexInference forwards it when set and does not synthesize a default, so omitting it returns Anthropic's own request error. `messageText(res)` pulls the assistant text out of the message `content`.
89
89
 
90
90
  ```ts
91
91
  import { messageText } from "flexinference";
@@ -104,7 +104,7 @@ console.log(messageText(res));
104
104
 
105
105
  Streaming and non-streaming requests are timed differently, so a long generation is never cut off yet a hung request never hangs forever:
106
106
 
107
- - **Non-streaming** requests have a total wall-clock budget: `timeout`, default **600000 ms (10 min)**, from send through the full body.
107
+ - **Non-streaming** requests have a body-read budget after response headers arrive: `timeout`, default **600000 ms (10 min)**. The worst case is roughly `firstByteTimeout + timeout`.
108
108
  - **Streaming** requests have **no total cap** (a healthy stream runs as long as tokens keep arriving). They are bounded by two clocks: `firstByteTimeout` (wait for the first response, default **60000 ms**) and `idleTimeout` (max silence between chunks before the stream is treated as hung, default **60000 ms**).
109
109
 
110
110
  The first-byte wait is **auto-raised for a flex `start_within`** (the router withholds response headers until the flex race resolves), so a long deadline just works. Raise `firstByteTimeout` yourself only for very large non-flex contexts whose first token is slow.
package/dist/index.d.ts CHANGED
@@ -5,7 +5,12 @@ type Schemas = components["schemas"];
5
5
  * those OpenAI service tiers and proxy any model; a duration "HHh-MMm-SSs" (5s-10m)
6
6
  * runs the flex race on a flex-capable model. An arbitrary string needs `as StartWithin`.
7
7
  */
8
- export type StartWithin = "default" | "priority" | "auto" | `${number}h-${number}m-${number}s`;
8
+ type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
9
+ type Second00To59 = "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | `1${Digit}` | `2${Digit}` | `3${Digit}` | `4${Digit}` | `5${Digit}`;
10
+ type Second05To59 = Exclude<Second00To59, "00" | "01" | "02" | "03" | "04">;
11
+ type Minute01To09 = `0${Exclude<Digit, "0">}`;
12
+ type Duration = `00h-00m-${Second05To59}s` | `00h-${Minute01To09}m-${Second00To59}s` | "00h-10m-00s";
13
+ export type StartWithin = "default" | "priority" | "auto" | Duration;
9
14
  /** Make `start_within` a required, typed field on a generated request body. */
10
15
  type WithStartWithin<T> = Omit<T, "start_within"> & {
11
16
  start_within: StartWithin;
@@ -78,6 +83,7 @@ export declare class FlexInferenceError extends Error {
78
83
  * FlexInferenceError)` handlers keep working; narrow to this to handle 402 specially.
79
84
  */
80
85
  export declare class PaymentRequiredError extends FlexInferenceError {
86
+ constructor(status: number, body: unknown, fallback: string);
81
87
  }
82
88
  export interface ClientOptions {
83
89
  apiKey: string;
@@ -86,9 +92,10 @@ export interface ClientOptions {
86
92
  /** Override the global fetch (e.g. for tests or non-standard runtimes). */
87
93
  fetch?: typeof fetch;
88
94
  /**
89
- * Non-streaming wall-clock budget in ms (from send through the full body). Defaults to
90
- * 600000 (10 min). Streaming requests ignore this: they are governed by `firstByteTimeout`
91
- * and `idleTimeout` and have no total cap, so a healthy long stream is never cut off.
95
+ * Non-streaming body-read budget in ms, after response headers arrive. Defaults to
96
+ * 600000 (10 min). The worst case is roughly `firstByteTimeout + timeout`.
97
+ * Streaming requests ignore this: they are governed by `firstByteTimeout` and
98
+ * `idleTimeout` and have no total cap, so a healthy long stream is never cut off.
92
99
  */
93
100
  timeout?: number;
94
101
  /**
package/dist/index.js CHANGED
@@ -120,6 +120,10 @@ export class FlexInferenceError extends Error {
120
120
  * FlexInferenceError)` handlers keep working; narrow to this to handle 402 specially.
121
121
  */
122
122
  export class PaymentRequiredError extends FlexInferenceError {
123
+ constructor(status, body, fallback) {
124
+ super(status, body, fallback);
125
+ this.name = "PaymentRequiredError";
126
+ }
123
127
  }
124
128
  const DEFAULT_BASE_URL = "https://api.flexinference.com/v1";
125
129
  // A streaming request is governed by two clocks and no total: how long we wait for the
@@ -134,43 +138,102 @@ const DEFAULT_TOTAL_MS = 600_000; // non-streaming wall-clock budget (streaming
134
138
  const ERROR_BODY_READ_MS = 30_000; // bound the read of a non-2xx error body
135
139
  // Cap the streaming buffer above the largest legitimate single frame (a terminal
136
140
  // response object is well under this). A stream that never sends a blank-line separator
137
- // would otherwise grow the buffer without bound; error clearly instead. See T2.
141
+ // would otherwise grow the buffer without bound; error clearly instead.
138
142
  const MAX_SSE_BUFFER_CHARS = 8 * 1024 * 1024;
139
143
  const MIN_DEADLINE_SECONDS = 5;
140
144
  const MAX_DEADLINE_SECONDS = 600;
141
145
  const SECONDS_PER_HOUR = 3600;
142
146
  const SECONDS_PER_MINUTE = 60;
143
- // One or two digits per field so the runtime accepts the same shapes the StartWithin
144
- // template-literal type does (e.g. "0h-5m-0s"): `${number}` in the type imposes no digit
145
- // count, so a two-digit-only regex would reject values that type-check. See T4.
146
- const DURATION_RE = /^(\d{1,2})h-(\d{1,2})m-(\d{1,2})s$/;
147
+ // Two digits per field so the runtime matches the router, Python SDK, and StartWithin type.
148
+ const DURATION_RE = /^(\d{2})h-(\d{2})m-(\d{2})s$/;
147
149
  const START_WITHIN_VALUES = '"default", "priority", "auto", or a duration "HHh-MMm-SSs"';
150
+ function startWithinValue(body) {
151
+ const value = typeof body === "object" && body !== null
152
+ ? body["start_within"]
153
+ : undefined;
154
+ return value === undefined ? { kind: "missing" } : { kind: "present", value };
155
+ }
156
+ function parseStartWithin(value) {
157
+ if (typeof value !== "string")
158
+ return { kind: "invalid", reason: "type", value };
159
+ if (value === "default" || value === "priority" || value === "auto") {
160
+ return { kind: "tier", value };
161
+ }
162
+ const match = DURATION_RE.exec(value);
163
+ if (match === null)
164
+ return { kind: "invalid", reason: "malformed", value };
165
+ const seconds = Number(match[1]) * SECONDS_PER_HOUR + Number(match[2]) * SECONDS_PER_MINUTE + Number(match[3]);
166
+ return { kind: "duration", value, seconds };
167
+ }
148
168
  // Runtime guard so plain-JS callers (who get no compile-time check) still fail
149
169
  // locally with a clear message instead of a provider round-trip. TypeScript callers
150
170
  // are already protected by the required StartWithin field above.
151
171
  function assertStartWithin(body) {
152
- const value = typeof body === "object" && body !== null
153
- ? body["start_within"]
154
- : undefined;
155
- if (value === undefined) {
172
+ const sw = startWithinValue(body);
173
+ if (sw.kind === "missing") {
156
174
  throw new Error(`FlexInference: \`start_within\` is required on every request. Set it to ${START_WITHIN_VALUES}, ` +
157
175
  `for example "start_within": "default" for standard-tier behavior or "00h-00m-30s" for a 30-second flex race.`);
158
176
  }
159
- if (typeof value !== "string") {
177
+ const parsed = parseStartWithin(sw.value);
178
+ if (parsed.kind === "invalid" && parsed.reason === "type") {
160
179
  throw new Error(`FlexInference: \`start_within\` must be a string (${START_WITHIN_VALUES}), for example "default".`);
161
180
  }
162
- if (value === "default" || value === "priority" || value === "auto")
163
- return;
164
- const match = DURATION_RE.exec(value);
165
- if (match === null) {
166
- throw new Error(`FlexInference: \`start_within\` "${value}" is not ${START_WITHIN_VALUES}. ` +
167
- `A duration is one or two digits each for hours, minutes, and seconds, for example "00h-05m-00s" for a 5-minute deadline.`);
181
+ if (parsed.kind === "invalid") {
182
+ throw new Error(`FlexInference: \`start_within\` "${parsed.value}" is not ${START_WITHIN_VALUES}. ` +
183
+ `A duration is two digits each for hours, minutes, and seconds, for example "00h-05m-00s" for a 5-minute deadline.`);
168
184
  }
169
- const seconds = Number(match[1]) * SECONDS_PER_HOUR + Number(match[2]) * SECONDS_PER_MINUTE + Number(match[3]);
170
- if (seconds < MIN_DEADLINE_SECONDS || seconds > MAX_DEADLINE_SECONDS) {
185
+ if (parsed.kind === "duration" &&
186
+ (parsed.seconds < MIN_DEADLINE_SECONDS || parsed.seconds > MAX_DEADLINE_SECONDS)) {
171
187
  throw new Error("FlexInference: `start_within` duration must be between 5s and 10m.");
172
188
  }
173
189
  }
190
+ // Per-endpoint required fields beyond the model/start_within envelope. Mirrors the Python
191
+ // _RequestSpec table in _validation.py: responses/interactions require `input` (presence only);
192
+ // chat/messages require `messages` (array).
193
+ const RESPONSES_REQUEST_SPEC = {
194
+ required: [{ name: "input", kind: "present" }],
195
+ };
196
+ const CHAT_REQUEST_SPEC = {
197
+ required: [{ name: "messages", kind: "array" }],
198
+ };
199
+ const INTERACTIONS_REQUEST_SPEC = {
200
+ required: [{ name: "input", kind: "present" }],
201
+ };
202
+ const MESSAGES_REQUEST_SPEC = {
203
+ required: [{ name: "messages", kind: "array" }],
204
+ };
205
+ // Read one field by reference off the raw body without copying it. `undefined` (or a non-object
206
+ // body) is treated as missing; `null` counts as present, matching Python's `name in body`
207
+ // presence check (a JSON `null` is a present key, and JSON serialization drops `undefined`).
208
+ function requestField(body, name) {
209
+ if (!isRecord(body))
210
+ return { kind: "missing" };
211
+ const value = body[name];
212
+ return value === undefined ? { kind: "missing" } : { kind: "present", value };
213
+ }
214
+ // Pre-flight guard: model, then start_within, then the endpoint's required fields in spec order.
215
+ // Pure - it only throws earlier for requests the router/Python already reject; it never mutates,
216
+ // clones, or reshapes the body, so unknown/extra fields pass straight through to `send`.
217
+ function validateRequest(spec, body) {
218
+ const model = requestField(body, "model");
219
+ if (model.kind === "missing" || typeof model.value !== "string" || model.value === "") {
220
+ throw new Error("FlexInference: `model` is required and must be a non-empty string.");
221
+ }
222
+ assertStartWithin(body);
223
+ for (const field of spec.required) {
224
+ const value = requestField(body, field.name);
225
+ if (value.kind === "missing") {
226
+ throw new Error(`FlexInference: \`${field.name}\` is required for this endpoint.`);
227
+ }
228
+ if (field.kind === "array" && !Array.isArray(value.value)) {
229
+ throw new Error(`FlexInference: \`${field.name}\` must be an array.`);
230
+ }
231
+ if (field.kind === "finiteNumber" &&
232
+ (typeof value.value !== "number" || !Number.isFinite(value.value))) {
233
+ throw new Error(`FlexInference: \`${field.name}\` must be a finite number.`);
234
+ }
235
+ }
236
+ }
174
237
  // Distinct abort reasons so an aborted fetch/read can be told apart: a timeout we fired
175
238
  // (turned into a clear message) versus the caller's own AbortSignal (propagated as-is).
176
239
  const FIRST_BYTE_TIMEOUT = Symbol("first-byte-timeout");
@@ -183,15 +246,11 @@ const TOTAL_TIMEOUT = Symbol("total-timeout");
183
246
  * clock must cover the whole deadline plus the fallback path.
184
247
  */
185
248
  function flexDeadlineSeconds(body) {
186
- const value = typeof body === "object" && body !== null
187
- ? body["start_within"]
188
- : undefined;
189
- if (typeof value !== "string")
249
+ const sw = startWithinValue(body);
250
+ if (sw.kind === "missing")
190
251
  return null;
191
- const match = DURATION_RE.exec(value);
192
- if (match === null)
193
- return null;
194
- return (Number(match[1]) * SECONDS_PER_HOUR + Number(match[2]) * SECONDS_PER_MINUTE + Number(match[3]));
252
+ const parsed = parseStartWithin(sw.value);
253
+ return parsed.kind === "duration" ? parsed.seconds : null;
195
254
  }
196
255
  // Read a non-streamed JSON body under the total wall-clock budget, then release the timer
197
256
  // and the abort listener. Non-streaming only: a stream is drained by streamSSE instead.
@@ -199,7 +258,7 @@ async function readJson(open) {
199
258
  const { res, controller, cleanup, totalMs } = open;
200
259
  // Abort with a dedicated reason so a fired total timeout can be told apart from the
201
260
  // caller cancelling on purpose, and translated into a clear message (parity with the
202
- // first-byte and idle timeouts, and with the Python SDK). See T1.
261
+ // first-byte and idle timeouts, and with the Python SDK).
203
262
  const totalTimer = setTimeout(() => {
204
263
  controller.abort(TOTAL_TIMEOUT);
205
264
  }, totalMs);
@@ -219,6 +278,13 @@ async function readJson(open) {
219
278
  cleanup();
220
279
  }
221
280
  }
281
+ async function createEndpoint(send, path, spec, body, options) {
282
+ validateRequest(spec, body);
283
+ const open = await send(path, body, options);
284
+ if (body.stream)
285
+ return streamSSE(open);
286
+ return readJson(open);
287
+ }
222
288
  export class FlexInference {
223
289
  responses;
224
290
  chat;
@@ -345,11 +411,7 @@ class Responses {
345
411
  this.send = send;
346
412
  }
347
413
  async create(body, options) {
348
- assertStartWithin(body);
349
- const open = await this.send("/responses", body, options);
350
- if (body.stream)
351
- return streamSSE(open);
352
- return readJson(open);
414
+ return createEndpoint(this.send, "/responses", RESPONSES_REQUEST_SPEC, body, options);
353
415
  }
354
416
  }
355
417
  class Chat {
@@ -364,11 +426,7 @@ class ChatCompletions {
364
426
  this.send = send;
365
427
  }
366
428
  async create(body, options) {
367
- assertStartWithin(body);
368
- const open = await this.send("/chat/completions", body, options);
369
- if (body.stream)
370
- return streamSSE(open);
371
- return readJson(open);
429
+ return createEndpoint(this.send, "/chat/completions", CHAT_REQUEST_SPEC, body, options);
372
430
  }
373
431
  }
374
432
  class Interactions {
@@ -377,11 +435,7 @@ class Interactions {
377
435
  this.send = send;
378
436
  }
379
437
  async create(body, options) {
380
- assertStartWithin(body);
381
- const open = await this.send("/interactions", body, options);
382
- if (body.stream)
383
- return streamSSE(open);
384
- return readJson(open);
438
+ return createEndpoint(this.send, "/interactions", INTERACTIONS_REQUEST_SPEC, body, options);
385
439
  }
386
440
  }
387
441
  class Messages {
@@ -390,11 +444,7 @@ class Messages {
390
444
  this.send = send;
391
445
  }
392
446
  async create(body, options) {
393
- assertStartWithin(body);
394
- const open = await this.send("/messages", body, options);
395
- if (body.stream)
396
- return streamSSE(open);
397
- return readJson(open);
447
+ return createEndpoint(this.send, "/messages", MESSAGES_REQUEST_SPEC, body, options);
398
448
  }
399
449
  }
400
450
  function parseSSEFrame(frame) {
@@ -445,7 +495,7 @@ async function* streamSSE(open) {
445
495
  if (done) {
446
496
  // The stream ended. Flush any bytes the decoder held back for an incomplete
447
497
  // multibyte sequence, then emit a final frame that arrived without its trailing
448
- // blank line so the last piece of the answer is not dropped. See T3.
498
+ // blank line so the last piece of the answer is not dropped.
449
499
  exhausted = true;
450
500
  buffer += decoder.decode();
451
501
  const frame = buffer;
@@ -473,7 +523,7 @@ async function* streamSSE(open) {
473
523
  }
474
524
  // With every complete frame drained, whatever remains is a single unterminated
475
525
  // frame. If it grows past the cap the stream is never sending a separator; error
476
- // clearly instead of buffering without bound. See T2.
526
+ // clearly instead of buffering without bound.
477
527
  if (buffer.length > MAX_SSE_BUFFER_CHARS) {
478
528
  throw new Error(`FlexInference: stream buffer exceeded ${String(MAX_SSE_BUFFER_CHARS)} characters ` +
479
529
  "without a frame boundary; aborting to avoid unbounded memory.");
package/dist/types.d.ts CHANGED
@@ -90,7 +90,7 @@ export interface paths {
90
90
  };
91
91
  get?: never;
92
92
  put?: never;
93
- /** Create a message. The fourth FlexInference caller format (Anthropic Messages shape in and out); works for any model via the canonical Responses path. Send start_within and do not send service_tier. max_tokens is required. */
93
+ /** Create a message. The fourth FlexInference caller format (Anthropic Messages shape in and out); works for any model via the canonical Responses path. Send start_within and do not send service_tier. Anthropic requires max_tokens upstream. FlexInference forwards it when set and does not synthesize a default, so omitting it returns Anthropic's own request error. */
94
94
  post: operations["createMessage"];
95
95
  delete?: never;
96
96
  options?: never;
@@ -5398,6 +5398,8 @@ export interface components {
5398
5398
  type: string;
5399
5399
  code?: string | null;
5400
5400
  param?: string | null;
5401
+ /** @description Additive deep link into the docs for this exact code. Present (a URL or null) on FlexInference-layer errors; absent on verbatim upstream errors. */
5402
+ doc_url?: string | null;
5401
5403
  };
5402
5404
  };
5403
5405
  /** Interaction Text Part */
@@ -5792,11 +5794,11 @@ export interface components {
5792
5794
  };
5793
5795
  /**
5794
5796
  * Message Create Params
5795
- * @description Request body for POST /v1/messages (Anthropic Messages shape). Works for any model via the canonical Responses path. max_tokens is required (Anthropic requires it and the router rejects a claude-* request that reaches the Anthropic upstream without a canonical max_output_tokens). Does not accept service_tier (the router owns the tier). start_within is required at runtime but left optional here.
5797
+ * @description Request body for POST /v1/messages (Anthropic Messages shape). Works for any model via the canonical Responses path. Anthropic requires max_tokens upstream. FlexInference forwards it when set and does not synthesize a default, so omitting it returns Anthropic's own request error. Does not accept service_tier (the router owns the tier). start_within is required at runtime but left optional here.
5796
5798
  */
5797
5799
  MessageCreateParams: {
5798
5800
  model: string;
5799
- max_tokens: number;
5801
+ max_tokens?: number;
5800
5802
  /** @description System prompt as a string or an array of text blocks. */
5801
5803
  system?: string | components["schemas"]["MessageTextBlock"][];
5802
5804
  messages: components["schemas"]["Message"][];
@@ -6134,7 +6136,7 @@ export interface operations {
6134
6136
  "text/event-stream": components["schemas"]["MessageStreamEvent"];
6135
6137
  };
6136
6138
  };
6137
- /** @description Bad request. A FlexInference-layer rejection (type flexinference_error, e.g. missing_start_within, invalid_start_within, model_not_flex_capable, flex_unsupported_for_anthropic, missing_max_tokens, service_tier_not_allowed) or an upstream provider rejection passed through unchanged. */
6139
+ /** @description Bad request. A FlexInference-layer rejection (type flexinference_error, e.g. missing_start_within, invalid_start_within, model_not_flex_capable, flex_unsupported_for_anthropic, service_tier_not_allowed) or an upstream provider rejection passed through unchanged. */
6138
6140
  400: {
6139
6141
  headers: {
6140
6142
  [name: string]: unknown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flexinference",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Official TypeScript SDK for FlexInference - a deadline-aware, OpenAI-compatible inference router.",
5
5
  "license": "MIT",
6
6
  "author": "Aditya Perswal <adityaperswal@gmail.com>",
@@ -34,7 +34,7 @@
34
34
  "build": "tsc -p tsconfig.json",
35
35
  "typecheck": "tsc -p tsconfig.json --noEmit",
36
36
  "test:types": "tsc -p tsconfig.test.json --noEmit",
37
- "test": "node test/smoke.mjs && node test/fixes.test.mjs && npm run test:types",
37
+ "test": "node test/smoke.mjs && node test/fixes.test.mjs && node test/parity.test.mjs && npm run test:types",
38
38
  "lint": "eslint .",
39
39
  "lint:fix": "eslint . --fix",
40
40
  "format": "prettier --write .",