flexinference 0.1.0 → 1.0.0

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 ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ The stable v1 of the FlexInference TypeScript SDK. This release makes `start_within`
6
+ required and aligns its values with OpenAI's `service_tier` vocabulary.
7
+
8
+ ### Breaking changes
9
+
10
+ - **`start_within` is now required on every request.** It is typed as
11
+ `StartWithin = "default" | "priority" | "auto" | \`${number}h-${number}m-${number}s\``,
12
+ so omitting it (or passing a value outside those shapes) is a **compile-time** error.
13
+ A duration that fits the shape but is malformed or out of range is caught at **runtime**;
14
+ plain-JS callers get every check at **runtime** (a thrown `Error` before any network call).
15
+ - **Accepted values changed.** `start_within` now takes `"default"`, `"priority"`,
16
+ `"auto"`, or a duration `"HHh-MMm-SSs"` (5s-10m). The old `"standard"` value is
17
+ removed; use `"default"` (it maps to the same OpenAI service tier).
18
+ - **Any model proxies for the non-flex values.** `"default"`, `"priority"`, and
19
+ `"auto"` proxy any model to OpenAI. Only the duration (flex race) requires a
20
+ flex-capable model; a duration on a non-flex-capable model returns the router's new
21
+ `model_not_flex_capable` error (the old `unsupported_model` is retired).
22
+
23
+ ### Added
24
+
25
+ - **Default request timeout.** Clients now bound every request: 10s to connect and
26
+ 600s (10 min) total, matching the router. Override the total with the new `timeout`
27
+ client option, still composable with a per-call `AbortSignal`.
28
+ - **`outputText(res)` helper.** Pulls the assistant's text out of a raw response
29
+ (Responses or chat completion) without hand-walking `output[].content[]`. The raw
30
+ wire body has no `output_text` field (that is computed by OpenAI's SDKs, not sent),
31
+ so this fills the gap. Read-only; nothing is reshaped.
32
+
33
+ ### Notes
34
+
35
+ - An arbitrary `string` is not assignable to `StartWithin`; use `value as StartWithin`
36
+ for a dynamically-built value.
37
+ - Validation is request-only: unknown fields pass straight through to the provider,
38
+ and responses are never validated or reshaped.
39
+
40
+ ### Migration
41
+
42
+ ```diff
43
+ - await client.responses.create({ model: "gpt-5.5", input: "hi" });
44
+ + await client.responses.create({ model: "gpt-5.5", input: "hi", start_within: "default" });
45
+
46
+ - start_within: "standard"
47
+ + start_within: "default"
48
+ ```
49
+
50
+ ## 0.1.0
51
+
52
+ - Initial release.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # FlexInference (TypeScript)
2
2
 
3
- The official TypeScript SDK for [FlexInference](https://flexinference.com) - a deadline-aware, OpenAI-compatible inference router. Send the OpenAI requests you already send, bring your own OpenAI key, and add one field - `start_within` - to trade latency for cost.
3
+ The official TypeScript SDK for [FlexInference](https://flexinference.com) - a deadline-aware, OpenAI-compatible inference router. Send the OpenAI requests you already send, bring your own OpenAI key, and set one required field - `start_within` - to trade latency for cost.
4
4
 
5
5
  ```bash
6
6
  npm install flexinference
@@ -9,7 +9,7 @@ npm install flexinference
9
9
  ## Quickstart
10
10
 
11
11
  ```ts
12
- import { FlexInference } from "flexinference";
12
+ import { FlexInference, outputText } from "flexinference";
13
13
 
14
14
  const client = new FlexInference({ apiKey: "flex_live_..." });
15
15
 
@@ -19,10 +19,12 @@ const res = await client.responses.create({
19
19
  start_within: "00h-00m-30s", // typed - no cast needed
20
20
  });
21
21
 
22
- console.log(res.output_text);
22
+ console.log(outputText(res));
23
23
  ```
24
24
 
25
- `start_within` takes `"priority"`, `"standard"`, or a duration `"HHh-MMm-SSs"` (5s-10m) that races OpenAI's flex tier and falls back to standard if it can't start in time. See the [docs](https://flexinference.com/docs/deadline-routing).
25
+ Responses come back as the **raw OpenAI JSON** (we never reshape the body), so there is no `output_text` field on the wire - that is computed by OpenAI's own SDKs. `outputText(res)` pulls the assistant's text out of either a response or a chat completion for you.
26
+
27
+ `start_within` is **required** on every request. It takes `"default"`, `"priority"`, `"auto"`, or a duration `"HHh-MMm-SSs"` (5s-10m). The duration races OpenAI's flex tier on a flex-capable model and falls back to standard if it can't start in time; `"default"`, `"priority"`, and `"auto"` map to those OpenAI service tiers and proxy any model. It is typed, so a missing value or a value outside the allowed shapes is a **compile-time** error; a duration that fits the shape but is malformed or out of range is caught at **runtime**, the same check plain-JavaScript callers get. See the [docs](https://flexinference.mintlify.app/deadline-routing).
26
28
 
27
29
  ## Streaming
28
30
 
@@ -47,27 +49,28 @@ The Chat Completions endpoint works identically:
47
49
  const res = await client.chat.completions.create({
48
50
  model: "gpt-5.5",
49
51
  messages: [{ role: "user", content: "Hello!" }],
50
- start_within: "standard",
52
+ start_within: "default",
51
53
  });
52
54
  ```
53
55
 
54
- ## Cancellation
56
+ ## Timeouts and cancellation
55
57
 
56
- Every call accepts an `AbortSignal` as a second argument, so you can cancel a request (or wire up your own timeout). Cancelling a stream stops it mid-flight:
58
+ Every client has a built-in timeout: **10 seconds to connect** and **600 seconds (10 min) total**, matching the router's budget, so a request can never hang forever. Override the total with the `timeout` option (raise it for very long streams):
57
59
 
58
60
  ```ts
59
- const controller = new AbortController();
60
- const timeout = setTimeout(() => controller.abort(), 5_000);
61
+ const client = new FlexInference({ apiKey: "flex_live_...", timeout: 120_000 });
62
+ ```
61
63
 
62
- try {
63
- const res = await client.responses.create(
64
- { model: "gpt-5.5", input: "Write a haiku about cheap GPUs.", start_within: "priority" },
65
- { signal: controller.signal },
66
- );
67
- console.log(res.output_text);
68
- } finally {
69
- clearTimeout(timeout);
70
- }
64
+ Every call also accepts an `AbortSignal` as a second argument, so you can cancel a request yourself. Cancelling a stream stops it mid-flight:
65
+
66
+ ```ts
67
+ const controller = new AbortController();
68
+ const res = await client.responses.create(
69
+ { model: "gpt-5.5", input: "Write a haiku about cheap GPUs.", start_within: "priority" },
70
+ { signal: controller.signal },
71
+ );
72
+ // controller.abort() from elsewhere to cancel
73
+ console.log(outputText(res));
71
74
  ```
72
75
 
73
76
  ## Errors
@@ -90,11 +93,12 @@ try {
90
93
 
91
94
  ## Configuration
92
95
 
93
- | Option | Default | Description |
94
- | --------- | ---------------------------------- | -------------------------------------- |
95
- | `apiKey` | - | Your `flex_live_` key (required). |
96
- | `baseURL` | `https://api.flexinference.com/v1` | Override the router endpoint. |
97
- | `fetch` | global `fetch` | Provide a custom fetch implementation. |
96
+ | Option | Default | Description |
97
+ | --------- | ---------------------------------- | ------------------------------------------------ |
98
+ | `apiKey` | - | Your `flex_live_` key (required). |
99
+ | `baseURL` | `https://api.flexinference.com/v1` | Override the router endpoint. |
100
+ | `fetch` | global `fetch` | Provide a custom fetch implementation. |
101
+ | `timeout` | `600000` | Total request budget in ms (connect capped 10s). |
98
102
 
99
103
  ## License
100
104
 
package/dist/index.d.ts CHANGED
@@ -1,11 +1,32 @@
1
1
  import type { components } from "./types.js";
2
2
  type Schemas = components["schemas"];
3
- export type ResponseCreateParams = Schemas["CreateResponse"];
3
+ /**
4
+ * The required FlexInference routing field. "default", "priority", and "auto" map to
5
+ * those OpenAI service tiers and proxy any model; a duration "HHh-MMm-SSs" (5s-10m)
6
+ * runs the flex race on a flex-capable model. An arbitrary string needs `as StartWithin`.
7
+ */
8
+ export type StartWithin = "default" | "priority" | "auto" | `${number}h-${number}m-${number}s`;
9
+ /** Make `start_within` a required, typed field on a generated request body. */
10
+ type WithStartWithin<T> = Omit<T, "start_within"> & {
11
+ start_within: StartWithin;
12
+ };
13
+ export type ResponseCreateParams = WithStartWithin<Schemas["CreateResponse"]>;
4
14
  export type ResponseObject = Schemas["Response"];
5
15
  export type ResponseStreamEvent = Schemas["ResponseStreamEvent"];
6
- export type ChatCompletionCreateParams = Schemas["CreateChatCompletionRequest"];
16
+ type RawChatRequest = Schemas["CreateChatCompletionRequest"];
17
+ export type ChatCompletionCreateParams = WithStartWithin<Partial<RawChatRequest> & Required<Pick<RawChatRequest, "model" | "messages">>>;
7
18
  export type ChatCompletion = Schemas["CreateChatCompletionResponse"];
8
19
  export type ChatCompletionChunk = Schemas["CreateChatCompletionStreamResponse"];
20
+ /**
21
+ * Concatenate the assistant's text from a non-streamed response. Works on a Responses
22
+ * object (walks `output[].content[]` for `output_text` parts) and on a chat completion
23
+ * (`choices[0].message.content`). Read-only: the raw body is never reshaped. Returns ""
24
+ * when there is no text (e.g. a tool-call-only or refusal response). The raw wire body
25
+ * has no `output_text` field - that is computed by OpenAI's own SDKs, not sent on the
26
+ * wire - so use this to pull the text out. Streamed responses are not objects; collect
27
+ * their `output_text.delta` events instead.
28
+ */
29
+ export declare function outputText(response: ResponseObject | ChatCompletion): string;
9
30
  export interface FlexErrorBody {
10
31
  error: {
11
32
  message: string;
@@ -27,17 +48,27 @@ export interface ClientOptions {
27
48
  baseURL?: string;
28
49
  /** Override the global fetch (e.g. for tests or non-standard runtimes). */
29
50
  fetch?: typeof fetch;
51
+ /**
52
+ * Total request budget in ms (connect through the full response/stream). Defaults
53
+ * to 600000 (10 min). Connect alone is capped at 10s. Raise it for very long streams.
54
+ */
55
+ timeout?: number;
30
56
  }
31
57
  export interface RequestOptions {
32
58
  signal?: AbortSignal;
33
59
  }
34
- type Post = (path: string, body: unknown, signal: AbortSignal | undefined) => Promise<Response>;
60
+ interface PostResult {
61
+ res: Response;
62
+ cleanup: () => void;
63
+ }
64
+ type Post = (path: string, body: unknown, signal: AbortSignal | undefined) => Promise<PostResult>;
35
65
  export declare class FlexInference {
36
66
  readonly responses: Responses;
37
67
  readonly chat: Chat;
38
68
  private readonly apiKey;
39
69
  private readonly baseURL;
40
70
  private readonly fetchImpl;
71
+ private readonly timeoutMs;
41
72
  constructor(options: ClientOptions);
42
73
  private post;
43
74
  }
package/dist/index.js CHANGED
@@ -1,3 +1,41 @@
1
+ function isRecord(value) {
2
+ return typeof value === "object" && value !== null;
3
+ }
4
+ /**
5
+ * Concatenate the assistant's text from a non-streamed response. Works on a Responses
6
+ * object (walks `output[].content[]` for `output_text` parts) and on a chat completion
7
+ * (`choices[0].message.content`). Read-only: the raw body is never reshaped. Returns ""
8
+ * when there is no text (e.g. a tool-call-only or refusal response). The raw wire body
9
+ * has no `output_text` field - that is computed by OpenAI's own SDKs, not sent on the
10
+ * wire - so use this to pull the text out. Streamed responses are not objects; collect
11
+ * their `output_text.delta` events instead.
12
+ */
13
+ export function outputText(response) {
14
+ const obj = response;
15
+ if (!isRecord(obj))
16
+ return "";
17
+ const output = obj.output;
18
+ if (Array.isArray(output)) {
19
+ let text = "";
20
+ for (const item of output) {
21
+ if (!isRecord(item) || item.type !== "message" || !Array.isArray(item.content))
22
+ continue;
23
+ for (const part of item.content) {
24
+ if (isRecord(part) && part.type === "output_text" && typeof part.text === "string") {
25
+ text += part.text;
26
+ }
27
+ }
28
+ }
29
+ return text;
30
+ }
31
+ const choices = obj.choices;
32
+ if (Array.isArray(choices) && isRecord(choices[0])) {
33
+ const message = choices[0].message;
34
+ if (isRecord(message) && typeof message.content === "string")
35
+ return message.content;
36
+ }
37
+ return "";
38
+ }
1
39
  export class FlexInferenceError extends Error {
2
40
  status;
3
41
  type;
@@ -14,17 +52,51 @@ export class FlexInferenceError extends Error {
14
52
  }
15
53
  }
16
54
  const DEFAULT_BASE_URL = "https://api.flexinference.com/v1";
55
+ const DEFAULT_TIMEOUT_MS = 600_000; // 10 min total budget, matching the router's generosity
56
+ const CONNECT_TIMEOUT_MS = 10_000; // fail fast if the router is unreachable
57
+ const MIN_DEADLINE_SECONDS = 5;
58
+ const MAX_DEADLINE_SECONDS = 600;
59
+ const SECONDS_PER_HOUR = 3600;
60
+ const SECONDS_PER_MINUTE = 60;
61
+ const DURATION_RE = /^(\d{2})h-(\d{2})m-(\d{2})s$/;
62
+ const START_WITHIN_VALUES = '"default", "priority", "auto", or a duration "HHh-MMm-SSs"';
63
+ // Runtime guard so plain-JS callers (who get no compile-time check) still fail
64
+ // locally with a clear message instead of a provider round-trip. TypeScript callers
65
+ // are already protected by the required StartWithin field above.
66
+ function assertStartWithin(body) {
67
+ const value = typeof body === "object" && body !== null
68
+ ? body["start_within"]
69
+ : undefined;
70
+ if (value === undefined) {
71
+ throw new Error(`FlexInference: \`start_within\` is required. Set it to ${START_WITHIN_VALUES}.`);
72
+ }
73
+ if (typeof value !== "string") {
74
+ throw new Error(`FlexInference: \`start_within\` must be a string (${START_WITHIN_VALUES}).`);
75
+ }
76
+ if (value === "default" || value === "priority" || value === "auto")
77
+ return;
78
+ const match = DURATION_RE.exec(value);
79
+ if (match === null) {
80
+ throw new Error(`FlexInference: \`start_within\` "${value}" is not ${START_WITHIN_VALUES}.`);
81
+ }
82
+ const seconds = Number(match[1]) * SECONDS_PER_HOUR + Number(match[2]) * SECONDS_PER_MINUTE + Number(match[3]);
83
+ if (seconds < MIN_DEADLINE_SECONDS || seconds > MAX_DEADLINE_SECONDS) {
84
+ throw new Error("FlexInference: `start_within` duration must be between 5s and 10m.");
85
+ }
86
+ }
17
87
  export class FlexInference {
18
88
  responses;
19
89
  chat;
20
90
  apiKey;
21
91
  baseURL;
22
92
  fetchImpl;
93
+ timeoutMs;
23
94
  constructor(options) {
24
95
  if (!options.apiKey)
25
96
  throw new Error("FlexInference: `apiKey` is required.");
26
97
  this.apiKey = options.apiKey;
27
98
  this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
99
+ this.timeoutMs = options.timeout ?? DEFAULT_TIMEOUT_MS;
28
100
  const f = options.fetch ?? globalThis.fetch;
29
101
  if (typeof f !== "function") {
30
102
  throw new Error("FlexInference: no global fetch found; pass `fetch` in options.");
@@ -35,17 +107,54 @@ export class FlexInference {
35
107
  this.chat = new Chat(post);
36
108
  }
37
109
  async post(path, body, signal) {
38
- const res = await this.fetchImpl(`${this.baseURL}${path}`, {
39
- method: "POST",
40
- headers: {
41
- Authorization: `Bearer ${this.apiKey}`,
42
- "Content-Type": "application/json",
43
- Accept: "text/event-stream, application/json",
44
- },
45
- body: JSON.stringify(body),
46
- signal,
47
- });
110
+ // One AbortController fed by three sources: the caller's signal, a 10s connect
111
+ // timer (cleared once headers arrive), and the total budget (cleared by the
112
+ // consumer once the body/stream is done). No dangling timers after completion.
113
+ const controller = new AbortController();
114
+ const onCallerAbort = () => {
115
+ controller.abort(signal?.reason);
116
+ };
117
+ if (signal) {
118
+ if (signal.aborted)
119
+ controller.abort(signal.reason);
120
+ else
121
+ signal.addEventListener("abort", onCallerAbort, { once: true });
122
+ }
123
+ const connectTimer = setTimeout(() => {
124
+ controller.abort();
125
+ }, CONNECT_TIMEOUT_MS);
126
+ const totalTimer = setTimeout(() => {
127
+ controller.abort();
128
+ }, this.timeoutMs);
129
+ const cleanup = () => {
130
+ clearTimeout(connectTimer);
131
+ clearTimeout(totalTimer);
132
+ signal?.removeEventListener("abort", onCallerAbort);
133
+ };
134
+ let res;
135
+ try {
136
+ res = await this.fetchImpl(`${this.baseURL}${path}`, {
137
+ method: "POST",
138
+ headers: {
139
+ Authorization: `Bearer ${this.apiKey}`,
140
+ "Content-Type": "application/json",
141
+ Accept: "text/event-stream, application/json",
142
+ },
143
+ body: JSON.stringify(body),
144
+ signal: controller.signal,
145
+ });
146
+ }
147
+ catch (err) {
148
+ cleanup();
149
+ if (controller.signal.aborted && signal?.aborted !== true) {
150
+ throw new Error(`FlexInference: request to the router timed out (connect ${String(CONNECT_TIMEOUT_MS)}ms / total ${String(this.timeoutMs)}ms).`);
151
+ }
152
+ throw err;
153
+ }
154
+ clearTimeout(connectTimer); // headers arrived; only the total budget governs the body now
48
155
  if (!res.ok) {
156
+ // Read the error body under the same timeout, then clear the timers. Clearing
157
+ // before the read would leave a stalled error body with no budget to abort it.
49
158
  let parsed;
50
159
  try {
51
160
  parsed = (await res.json());
@@ -53,9 +162,12 @@ export class FlexInference {
53
162
  catch {
54
163
  parsed = undefined;
55
164
  }
165
+ finally {
166
+ cleanup();
167
+ }
56
168
  throw new FlexInferenceError(res.status, parsed, `HTTP ${String(res.status)} ${res.statusText}`);
57
169
  }
58
- return res;
170
+ return { res, cleanup };
59
171
  }
60
172
  }
61
173
  class Responses {
@@ -64,11 +176,17 @@ class Responses {
64
176
  this.post = post;
65
177
  }
66
178
  async create(body, options) {
67
- const res = await this.post("/responses", body, options?.signal);
179
+ assertStartWithin(body);
180
+ const { res, cleanup } = await this.post("/responses", body, options?.signal);
68
181
  if (body.stream) {
69
- return streamSSE(res);
182
+ return streamSSE(res, cleanup);
183
+ }
184
+ try {
185
+ return (await res.json());
186
+ }
187
+ finally {
188
+ cleanup();
70
189
  }
71
- return (await res.json());
72
190
  }
73
191
  }
74
192
  class Chat {
@@ -83,24 +201,35 @@ class ChatCompletions {
83
201
  this.post = post;
84
202
  }
85
203
  async create(body, options) {
86
- const res = await this.post("/chat/completions", body, options?.signal);
204
+ assertStartWithin(body);
205
+ const { res, cleanup } = await this.post("/chat/completions", body, options?.signal);
87
206
  if (body.stream) {
88
- return streamSSE(res);
207
+ return streamSSE(res, cleanup);
208
+ }
209
+ try {
210
+ return (await res.json());
211
+ }
212
+ finally {
213
+ cleanup();
89
214
  }
90
- return (await res.json());
91
215
  }
92
216
  }
93
- async function* streamSSE(res) {
94
- if (!res.body)
217
+ async function* streamSSE(res, cleanup) {
218
+ if (!res.body) {
219
+ cleanup();
95
220
  throw new Error("FlexInference: streaming response has no body.");
221
+ }
96
222
  const reader = res.body.getReader();
97
223
  const decoder = new TextDecoder();
98
224
  let buffer = "";
225
+ let exhausted = false;
99
226
  try {
100
227
  for (;;) {
101
228
  const { done, value } = await reader.read();
102
- if (done)
229
+ if (done) {
230
+ exhausted = true;
103
231
  break;
232
+ }
104
233
  buffer += decoder.decode(value, { stream: true }).replace(/\r/g, "");
105
234
  let sep;
106
235
  while ((sep = buffer.indexOf("\n\n")) !== -1) {
@@ -114,13 +243,26 @@ async function* streamSSE(res) {
114
243
  if (dataLines.length === 0)
115
244
  continue;
116
245
  const data = dataLines.join("\n");
117
- if (data === "[DONE]")
246
+ if (data === "[DONE]") {
247
+ exhausted = true;
118
248
  return;
249
+ }
119
250
  yield JSON.parse(data);
120
251
  }
121
252
  }
122
253
  }
123
254
  finally {
124
- reader.releaseLock();
255
+ // A consumer that breaks early (or a parse that throws) leaves the body undrained.
256
+ // Cancel it so the socket is released now instead of lingering until GC; a fully
257
+ // drained stream just releases the lock.
258
+ if (exhausted) {
259
+ reader.releaseLock();
260
+ }
261
+ else {
262
+ await reader.cancel().catch(() => {
263
+ // already cancelled or the body errored; nothing to release
264
+ });
265
+ }
266
+ cleanup();
125
267
  }
126
268
  }
package/dist/types.d.ts CHANGED
@@ -1105,7 +1105,7 @@ export interface components {
1105
1105
  */
1106
1106
  top_logprobs?: number;
1107
1107
  /**
1108
- * @description FlexInference deadline control. "priority" or "standard" route the request to those OpenAI service tiers. A duration "XXh-YYm-ZZs" between 5 seconds and 10 minutes runs the flex tier and automatically falls back to standard if it has not started within the window.
1108
+ * @description FlexInference deadline control. Required on every request. "default", "priority", and "auto" map to those OpenAI service tiers ("auto" lets OpenAI pick) and proxy any model. A duration "HHh-MMm-SSs" between 5 seconds and 10 minutes runs the flex tier on a flex-capable model and automatically falls back to standard if it has not started within the window. The retired value "standard" is no longer accepted (use "default").
1109
1109
  * @example 00h-00m-30s
1110
1110
  */
1111
1111
  start_within?: string;
@@ -1773,7 +1773,7 @@ export interface components {
1773
1773
  /**
1774
1774
  * @description Labels an `assistant` message as intermediate commentary (`commentary`) or the final answer (`final_answer`).
1775
1775
  * For models like `gpt-5.3-codex` and beyond, when sending follow-up requests, preserve and resend
1776
- * phase on all assistant messages - dropping it can degrade performance. Not used for user messages.
1776
+ * phase on all assistant messages dropping it can degrade performance. Not used for user messages.
1777
1777
  * @enum {string}
1778
1778
  */
1779
1779
  MessagePhase: "commentary" | "final_answer";
@@ -5398,7 +5398,7 @@ export interface operations {
5398
5398
  "text/event-stream": components["schemas"]["CreateChatCompletionStreamResponse"];
5399
5399
  };
5400
5400
  };
5401
- /** @description Bad request. A FlexInference-layer rejection (type flexinference_error, e.g. invalid_start_within, unsupported_model, no_byok_key) or an OpenAI rejection passed through unchanged. */
5401
+ /** @description Bad request. A FlexInference-layer rejection (type flexinference_error, e.g. missing_start_within, invalid_start_within, model_not_flex_capable, no_byok_key) or an OpenAI rejection passed through unchanged. */
5402
5402
  400: {
5403
5403
  headers: {
5404
5404
  [name: string]: unknown;
@@ -5441,7 +5441,7 @@ export interface operations {
5441
5441
  "text/event-stream": components["schemas"]["ResponseStreamEvent"];
5442
5442
  };
5443
5443
  };
5444
- /** @description Bad request. A FlexInference-layer rejection (type flexinference_error, e.g. invalid_start_within, unsupported_model, no_byok_key) or an OpenAI rejection passed through unchanged. */
5444
+ /** @description Bad request. A FlexInference-layer rejection (type flexinference_error, e.g. missing_start_within, invalid_start_within, model_not_flex_capable, no_byok_key) or an OpenAI rejection passed through unchanged. */
5445
5445
  400: {
5446
5446
  headers: {
5447
5447
  [name: string]: unknown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flexinference",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
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>",
@@ -27,11 +27,14 @@
27
27
  "files": [
28
28
  "dist",
29
29
  "README.md",
30
+ "CHANGELOG.md",
30
31
  "LICENSE"
31
32
  ],
32
33
  "scripts": {
33
34
  "build": "tsc -p tsconfig.json",
34
35
  "typecheck": "tsc -p tsconfig.json --noEmit",
36
+ "test:types": "tsc -p tsconfig.test.json --noEmit",
37
+ "test": "node test/smoke.mjs && npm run test:types",
35
38
  "lint": "eslint .",
36
39
  "lint:fix": "eslint . --fix",
37
40
  "format": "prettier --write .",