@huggingface/inference 3.14.0 → 4.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.
Files changed (130) hide show
  1. package/README.md +104 -1
  2. package/dist/commonjs/errors.d.ts +46 -0
  3. package/dist/commonjs/errors.d.ts.map +1 -0
  4. package/dist/commonjs/errors.js +70 -0
  5. package/dist/commonjs/index.d.ts +1 -1
  6. package/dist/commonjs/index.d.ts.map +1 -1
  7. package/dist/commonjs/index.js +2 -3
  8. package/dist/commonjs/lib/getInferenceProviderMapping.d.ts.map +1 -1
  9. package/dist/commonjs/lib/getInferenceProviderMapping.js +27 -16
  10. package/dist/commonjs/lib/getProviderHelper.d.ts.map +1 -1
  11. package/dist/commonjs/lib/getProviderHelper.js +5 -3
  12. package/dist/commonjs/lib/makeRequestOptions.d.ts.map +1 -1
  13. package/dist/commonjs/lib/makeRequestOptions.js +12 -11
  14. package/dist/commonjs/package.d.ts +1 -1
  15. package/dist/commonjs/package.d.ts.map +1 -1
  16. package/dist/commonjs/package.js +1 -1
  17. package/dist/commonjs/providers/black-forest-labs.d.ts.map +1 -1
  18. package/dist/commonjs/providers/black-forest-labs.js +4 -4
  19. package/dist/commonjs/providers/fal-ai.d.ts.map +1 -1
  20. package/dist/commonjs/providers/fal-ai.js +29 -17
  21. package/dist/commonjs/providers/featherless-ai.d.ts.map +1 -1
  22. package/dist/commonjs/providers/featherless-ai.js +10 -4
  23. package/dist/commonjs/providers/hf-inference.d.ts.map +1 -1
  24. package/dist/commonjs/providers/hf-inference.js +27 -30
  25. package/dist/commonjs/providers/hyperbolic.d.ts.map +1 -1
  26. package/dist/commonjs/providers/hyperbolic.js +3 -3
  27. package/dist/commonjs/providers/nebius.d.ts.map +1 -1
  28. package/dist/commonjs/providers/nebius.js +2 -2
  29. package/dist/commonjs/providers/novita.d.ts +5 -6
  30. package/dist/commonjs/providers/novita.d.ts.map +1 -1
  31. package/dist/commonjs/providers/novita.js +66 -16
  32. package/dist/commonjs/providers/nscale.d.ts.map +1 -1
  33. package/dist/commonjs/providers/nscale.js +2 -2
  34. package/dist/commonjs/providers/ovhcloud.d.ts.map +1 -1
  35. package/dist/commonjs/providers/ovhcloud.js +2 -2
  36. package/dist/commonjs/providers/providerHelper.js +3 -3
  37. package/dist/commonjs/providers/replicate.js +4 -4
  38. package/dist/commonjs/providers/sambanova.d.ts +16 -0
  39. package/dist/commonjs/providers/sambanova.d.ts.map +1 -1
  40. package/dist/commonjs/providers/sambanova.js +2 -18
  41. package/dist/commonjs/providers/together.d.ts.map +1 -1
  42. package/dist/commonjs/providers/together.js +3 -3
  43. package/dist/commonjs/tasks/audio/automaticSpeechRecognition.d.ts.map +1 -1
  44. package/dist/commonjs/tasks/audio/automaticSpeechRecognition.js +2 -2
  45. package/dist/commonjs/utils/request.d.ts.map +1 -1
  46. package/dist/commonjs/utils/request.js +77 -12
  47. package/dist/commonjs/vendor/type-fest/basic.d.ts +33 -0
  48. package/dist/commonjs/vendor/type-fest/basic.d.ts.map +1 -0
  49. package/dist/commonjs/vendor/type-fest/basic.js +2 -0
  50. package/dist/esm/errors.d.ts +46 -0
  51. package/dist/esm/errors.d.ts.map +1 -0
  52. package/dist/esm/errors.js +62 -0
  53. package/dist/esm/index.d.ts +1 -1
  54. package/dist/esm/index.d.ts.map +1 -1
  55. package/dist/esm/index.js +1 -1
  56. package/dist/esm/lib/getInferenceProviderMapping.d.ts.map +1 -1
  57. package/dist/esm/lib/getInferenceProviderMapping.js +27 -16
  58. package/dist/esm/lib/getProviderHelper.d.ts.map +1 -1
  59. package/dist/esm/lib/getProviderHelper.js +5 -3
  60. package/dist/esm/lib/makeRequestOptions.d.ts.map +1 -1
  61. package/dist/esm/lib/makeRequestOptions.js +12 -11
  62. package/dist/esm/package.d.ts +1 -1
  63. package/dist/esm/package.d.ts.map +1 -1
  64. package/dist/esm/package.js +1 -1
  65. package/dist/esm/providers/black-forest-labs.d.ts.map +1 -1
  66. package/dist/esm/providers/black-forest-labs.js +4 -4
  67. package/dist/esm/providers/fal-ai.d.ts.map +1 -1
  68. package/dist/esm/providers/fal-ai.js +29 -17
  69. package/dist/esm/providers/featherless-ai.d.ts.map +1 -1
  70. package/dist/esm/providers/featherless-ai.js +10 -4
  71. package/dist/esm/providers/hf-inference.d.ts.map +1 -1
  72. package/dist/esm/providers/hf-inference.js +27 -30
  73. package/dist/esm/providers/hyperbolic.d.ts.map +1 -1
  74. package/dist/esm/providers/hyperbolic.js +3 -3
  75. package/dist/esm/providers/nebius.d.ts.map +1 -1
  76. package/dist/esm/providers/nebius.js +2 -2
  77. package/dist/esm/providers/novita.d.ts +5 -6
  78. package/dist/esm/providers/novita.d.ts.map +1 -1
  79. package/dist/esm/providers/novita.js +66 -16
  80. package/dist/esm/providers/nscale.d.ts.map +1 -1
  81. package/dist/esm/providers/nscale.js +2 -2
  82. package/dist/esm/providers/ovhcloud.d.ts.map +1 -1
  83. package/dist/esm/providers/ovhcloud.js +2 -2
  84. package/dist/esm/providers/providerHelper.js +3 -3
  85. package/dist/esm/providers/replicate.js +4 -4
  86. package/dist/esm/providers/sambanova.d.ts +16 -0
  87. package/dist/esm/providers/sambanova.d.ts.map +1 -1
  88. package/dist/esm/providers/sambanova.js +2 -18
  89. package/dist/esm/providers/together.d.ts.map +1 -1
  90. package/dist/esm/providers/together.js +3 -3
  91. package/dist/esm/tasks/audio/automaticSpeechRecognition.d.ts.map +1 -1
  92. package/dist/esm/tasks/audio/automaticSpeechRecognition.js +2 -2
  93. package/dist/esm/utils/request.d.ts.map +1 -1
  94. package/dist/esm/utils/request.js +77 -12
  95. package/dist/esm/vendor/type-fest/basic.d.ts +33 -0
  96. package/dist/esm/vendor/type-fest/basic.d.ts.map +1 -0
  97. package/dist/esm/vendor/type-fest/basic.js +1 -0
  98. package/package.json +2 -2
  99. package/src/errors.ts +82 -0
  100. package/src/index.ts +1 -1
  101. package/src/lib/getInferenceProviderMapping.ts +42 -22
  102. package/src/lib/getProviderHelper.ts +9 -3
  103. package/src/lib/makeRequestOptions.ts +20 -11
  104. package/src/package.ts +1 -1
  105. package/src/providers/black-forest-labs.ts +14 -4
  106. package/src/providers/fal-ai.ts +59 -23
  107. package/src/providers/featherless-ai.ts +10 -4
  108. package/src/providers/hf-inference.ts +75 -34
  109. package/src/providers/hyperbolic.ts +3 -4
  110. package/src/providers/nebius.ts +2 -2
  111. package/src/providers/novita.ts +103 -23
  112. package/src/providers/nscale.ts +2 -2
  113. package/src/providers/ovhcloud.ts +2 -2
  114. package/src/providers/providerHelper.ts +3 -3
  115. package/src/providers/replicate.ts +4 -4
  116. package/src/providers/sambanova.ts +3 -4
  117. package/src/providers/together.ts +3 -3
  118. package/src/tasks/audio/automaticSpeechRecognition.ts +2 -2
  119. package/src/tasks/cv/textToVideo.ts +2 -2
  120. package/src/utils/request.ts +127 -14
  121. package/src/vendor/type-fest/basic.ts +31 -0
  122. package/src/vendor/type-fest/license-cc0 +121 -0
  123. package/src/vendor/type-fest/license-mit +9 -0
  124. package/dist/commonjs/lib/InferenceOutputError.d.ts +0 -4
  125. package/dist/commonjs/lib/InferenceOutputError.d.ts.map +0 -1
  126. package/dist/commonjs/lib/InferenceOutputError.js +0 -10
  127. package/dist/esm/lib/InferenceOutputError.d.ts +0 -4
  128. package/dist/esm/lib/InferenceOutputError.d.ts.map +0 -1
  129. package/dist/esm/lib/InferenceOutputError.js +0 -6
  130. package/src/lib/InferenceOutputError.ts +0 -8
@@ -14,9 +14,10 @@
14
14
  *
15
15
  * Thanks!
16
16
  */
17
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
18
17
  import { isUrl } from "../lib/isUrl.js";
18
+ import type { TextToVideoArgs } from "../tasks/index.js";
19
19
  import type { BodyParams, UrlParams } from "../types.js";
20
+ import { delay } from "../utils/delay.js";
20
21
  import { omit } from "../utils/omit.js";
21
22
  import {
22
23
  BaseConversationalTask,
@@ -24,13 +25,18 @@ import {
24
25
  TaskProviderHelper,
25
26
  type TextToVideoTaskHelper,
26
27
  } from "./providerHelper.js";
28
+ import {
29
+ InferenceClientInputError,
30
+ InferenceClientProviderApiError,
31
+ InferenceClientProviderOutputError,
32
+ } from "../errors.js";
27
33
 
28
34
  const NOVITA_API_BASE_URL = "https://api.novita.ai";
29
- export interface NovitaOutput {
30
- video: {
31
- video_url: string;
32
- };
35
+
36
+ export interface NovitaAsyncAPIOutput {
37
+ task_id: string;
33
38
  }
39
+
34
40
  export class NovitaTextGenerationTask extends BaseTextGenerationTask {
35
41
  constructor() {
36
42
  super("novita", NOVITA_API_BASE_URL);
@@ -50,38 +56,112 @@ export class NovitaConversationalTask extends BaseConversationalTask {
50
56
  return "/v3/openai/chat/completions";
51
57
  }
52
58
  }
59
+
53
60
  export class NovitaTextToVideoTask extends TaskProviderHelper implements TextToVideoTaskHelper {
54
61
  constructor() {
55
62
  super("novita", NOVITA_API_BASE_URL);
56
63
  }
57
64
 
58
- makeRoute(params: UrlParams): string {
59
- return `/v3/hf/${params.model}`;
65
+ override makeRoute(params: UrlParams): string {
66
+ return `/v3/async/${params.model}`;
60
67
  }
61
68
 
62
- preparePayload(params: BodyParams): Record<string, unknown> {
69
+ override preparePayload(params: BodyParams<TextToVideoArgs>): Record<string, unknown> {
70
+ const { num_inference_steps, ...restParameters } = params.args.parameters ?? {};
63
71
  return {
64
72
  ...omit(params.args, ["inputs", "parameters"]),
65
- ...(params.args.parameters as Record<string, unknown>),
73
+ ...restParameters,
74
+ steps: num_inference_steps,
66
75
  prompt: params.args.inputs,
67
76
  };
68
77
  }
69
- override async getResponse(response: NovitaOutput): Promise<Blob> {
70
- const isValidOutput =
71
- typeof response === "object" &&
72
- !!response &&
73
- "video" in response &&
74
- typeof response.video === "object" &&
75
- !!response.video &&
76
- "video_url" in response.video &&
77
- typeof response.video.video_url === "string" &&
78
- isUrl(response.video.video_url);
79
78
 
80
- if (!isValidOutput) {
81
- throw new InferenceOutputError("Expected { video: { video_url: string } }");
79
+ override async getResponse(
80
+ response: NovitaAsyncAPIOutput,
81
+ url?: string,
82
+ headers?: Record<string, string>
83
+ ): Promise<Blob> {
84
+ if (!url || !headers) {
85
+ throw new InferenceClientInputError("URL and headers are required for text-to-video task");
86
+ }
87
+ const taskId = response.task_id;
88
+ if (!taskId) {
89
+ throw new InferenceClientProviderOutputError(
90
+ "Received malformed response from Novita text-to-video API: no task ID found in the response"
91
+ );
92
+ }
93
+
94
+ const parsedUrl = new URL(url);
95
+ const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}${
96
+ parsedUrl.host === "router.huggingface.co" ? "/novita" : ""
97
+ }`;
98
+ const resultUrl = `${baseUrl}/v3/async/task-result?task_id=${taskId}`;
99
+
100
+ let status = "";
101
+ let taskResult: unknown;
102
+
103
+ while (status !== "TASK_STATUS_SUCCEED" && status !== "TASK_STATUS_FAILED") {
104
+ await delay(500);
105
+ const resultResponse = await fetch(resultUrl, { headers });
106
+ if (!resultResponse.ok) {
107
+ throw new InferenceClientProviderApiError(
108
+ "Failed to fetch task result",
109
+ { url: resultUrl, method: "GET", headers },
110
+ {
111
+ requestId: resultResponse.headers.get("x-request-id") ?? "",
112
+ status: resultResponse.status,
113
+ body: await resultResponse.text(),
114
+ }
115
+ );
116
+ }
117
+ try {
118
+ taskResult = await resultResponse.json();
119
+ if (
120
+ taskResult &&
121
+ typeof taskResult === "object" &&
122
+ "task" in taskResult &&
123
+ taskResult.task &&
124
+ typeof taskResult.task === "object" &&
125
+ "status" in taskResult.task &&
126
+ typeof taskResult.task.status === "string"
127
+ ) {
128
+ status = taskResult.task.status;
129
+ } else {
130
+ throw new InferenceClientProviderOutputError(
131
+ "Received malformed response from Novita text-to-video API: failed to get task status"
132
+ );
133
+ }
134
+ } catch (error) {
135
+ throw new InferenceClientProviderOutputError(
136
+ "Received malformed response from Novita text-to-video API: failed to parse task result"
137
+ );
138
+ }
82
139
  }
83
140
 
84
- const urlResponse = await fetch(response.video.video_url);
85
- return await urlResponse.blob();
141
+ if (status === "TASK_STATUS_FAILED") {
142
+ throw new InferenceClientProviderOutputError("Novita text-to-video task failed");
143
+ }
144
+
145
+ if (
146
+ typeof taskResult === "object" &&
147
+ !!taskResult &&
148
+ "videos" in taskResult &&
149
+ typeof taskResult.videos === "object" &&
150
+ !!taskResult.videos &&
151
+ Array.isArray(taskResult.videos) &&
152
+ taskResult.videos.length > 0 &&
153
+ "video_url" in taskResult.videos[0] &&
154
+ typeof taskResult.videos[0].video_url === "string" &&
155
+ isUrl(taskResult.videos[0].video_url)
156
+ ) {
157
+ const urlResponse = await fetch(taskResult.videos[0].video_url);
158
+ return await urlResponse.blob();
159
+ } else {
160
+ throw new InferenceClientProviderOutputError(
161
+ `Received malformed response from Novita text-to-video API: expected { videos: [{ video_url: string }] } format, got instead: ${JSON.stringify(
162
+ taskResult
163
+ )}`
164
+ );
165
+ }
86
166
  }
87
167
  }
@@ -15,10 +15,10 @@
15
15
  * Thanks!
16
16
  */
17
17
  import type { TextToImageInput } from "@huggingface/tasks";
18
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
19
18
  import type { BodyParams } from "../types.js";
20
19
  import { omit } from "../utils/omit.js";
21
20
  import { BaseConversationalTask, TaskProviderHelper, type TextToImageTaskHelper } from "./providerHelper.js";
21
+ import { InferenceClientProviderOutputError } from "../errors.js";
22
22
 
23
23
  const NSCALE_API_BASE_URL = "https://inference.api.nscale.com";
24
24
 
@@ -74,6 +74,6 @@ export class NscaleTextToImageTask extends TaskProviderHelper implements TextToI
74
74
  return fetch(`data:image/jpeg;base64,${base64Data}`).then((res) => res.blob());
75
75
  }
76
76
 
77
- throw new InferenceOutputError("Expected Nscale text-to-image response format");
77
+ throw new InferenceClientProviderOutputError("Received malformed response from Nscale text-to-image API");
78
78
  }
79
79
  }
@@ -17,10 +17,10 @@
17
17
 
18
18
  import { BaseConversationalTask, BaseTextGenerationTask } from "./providerHelper.js";
19
19
  import type { ChatCompletionOutput, TextGenerationOutput, TextGenerationOutputFinishReason } from "@huggingface/tasks";
20
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
21
20
  import type { BodyParams } from "../types.js";
22
21
  import { omit } from "../utils/omit.js";
23
22
  import type { TextGenerationInput } from "@huggingface/tasks";
23
+ import { InferenceClientProviderOutputError } from "../errors.js";
24
24
 
25
25
  const OVHCLOUD_API_BASE_URL = "https://oai.endpoints.kepler.ai.cloud.ovh.net";
26
26
 
@@ -70,6 +70,6 @@ export class OvhCloudTextGenerationTask extends BaseTextGenerationTask {
70
70
  generated_text: completion.text,
71
71
  };
72
72
  }
73
- throw new InferenceOutputError("Expected OVHcloud text generation response format");
73
+ throw new InferenceClientProviderOutputError("Received malformed response from OVHcloud text generation API");
74
74
  }
75
75
  }
@@ -46,7 +46,7 @@ import type {
46
46
  ZeroShotImageClassificationOutput,
47
47
  } from "@huggingface/tasks";
48
48
  import { HF_ROUTER_URL } from "../config.js";
49
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
49
+ import { InferenceClientProviderOutputError } from "../errors.js";
50
50
  import type { AudioToAudioOutput } from "../tasks/audio/audioToAudio.js";
51
51
  import type { BaseArgs, BodyParams, HeaderParams, InferenceProvider, RequestArgs, UrlParams } from "../types.js";
52
52
  import { toArray } from "../utils/toArray.js";
@@ -320,7 +320,7 @@ export class BaseConversationalTask extends TaskProviderHelper implements Conver
320
320
  return response;
321
321
  }
322
322
 
323
- throw new InferenceOutputError("Expected ChatCompletionOutput");
323
+ throw new InferenceClientProviderOutputError("Expected ChatCompletionOutput");
324
324
  }
325
325
  }
326
326
 
@@ -353,6 +353,6 @@ export class BaseTextGenerationTask extends TaskProviderHelper implements TextGe
353
353
  return res[0];
354
354
  }
355
355
 
356
- throw new InferenceOutputError("Expected Array<{generated_text: string}>");
356
+ throw new InferenceClientProviderOutputError("Expected Array<{generated_text: string}>");
357
357
  }
358
358
  }
@@ -14,7 +14,7 @@
14
14
  *
15
15
  * Thanks!
16
16
  */
17
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
17
+ import { InferenceClientProviderOutputError } from "../errors.js";
18
18
  import { isUrl } from "../lib/isUrl.js";
19
19
  import type { BodyParams, HeaderParams, UrlParams } from "../types.js";
20
20
  import { omit } from "../utils/omit.js";
@@ -99,7 +99,7 @@ export class ReplicateTextToImageTask extends ReplicateTask implements TextToIma
99
99
  return await urlResponse.blob();
100
100
  }
101
101
 
102
- throw new InferenceOutputError("Expected Replicate text-to-image response format");
102
+ throw new InferenceClientProviderOutputError("Received malformed response from Replicate text-to-image API");
103
103
  }
104
104
  }
105
105
 
@@ -132,7 +132,7 @@ export class ReplicateTextToSpeechTask extends ReplicateTask {
132
132
  }
133
133
  }
134
134
  }
135
- throw new InferenceOutputError("Expected Blob or object with output");
135
+ throw new InferenceClientProviderOutputError("Received malformed response from Replicate text-to-speech API");
136
136
  }
137
137
  }
138
138
 
@@ -149,6 +149,6 @@ export class ReplicateTextToVideoTask extends ReplicateTask implements TextToVid
149
149
  return await urlResponse.blob();
150
150
  }
151
151
 
152
- throw new InferenceOutputError("Expected { output: string }");
152
+ throw new InferenceClientProviderOutputError("Received malformed response from Replicate text-to-video API");
153
153
  }
154
154
  }
@@ -14,12 +14,11 @@
14
14
  *
15
15
  * Thanks!
16
16
  */
17
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
18
-
19
17
  import type { FeatureExtractionOutput } from "@huggingface/tasks";
20
18
  import type { BodyParams } from "../types.js";
21
19
  import type { FeatureExtractionTaskHelper } from "./providerHelper.js";
22
20
  import { BaseConversationalTask, TaskProviderHelper } from "./providerHelper.js";
21
+ import { InferenceClientProviderOutputError } from "../errors.js";
23
22
 
24
23
  export class SambanovaConversationalTask extends BaseConversationalTask {
25
24
  constructor() {
@@ -40,8 +39,8 @@ export class SambanovaFeatureExtractionTask extends TaskProviderHelper implement
40
39
  if (typeof response === "object" && "data" in response && Array.isArray(response.data)) {
41
40
  return response.data.map((item) => item.embedding);
42
41
  }
43
- throw new InferenceOutputError(
44
- "Expected Sambanova feature-extraction (embeddings) response format to be {'data' : list of {'embedding' : number[]}}"
42
+ throw new InferenceClientProviderOutputError(
43
+ "Received malformed response from Sambanova feature-extraction (embeddings) API"
45
44
  );
46
45
  }
47
46
 
@@ -15,7 +15,6 @@
15
15
  * Thanks!
16
16
  */
17
17
  import type { ChatCompletionOutput, TextGenerationOutput, TextGenerationOutputFinishReason } from "@huggingface/tasks";
18
- import { InferenceOutputError } from "../lib/InferenceOutputError.js";
19
18
  import type { BodyParams } from "../types.js";
20
19
  import { omit } from "../utils/omit.js";
21
20
  import {
@@ -24,6 +23,7 @@ import {
24
23
  TaskProviderHelper,
25
24
  type TextToImageTaskHelper,
26
25
  } from "./providerHelper.js";
26
+ import { InferenceClientProviderOutputError } from "../errors.js";
27
27
 
28
28
  const TOGETHER_API_BASE_URL = "https://api.together.xyz";
29
29
 
@@ -74,7 +74,7 @@ export class TogetherTextGenerationTask extends BaseTextGenerationTask {
74
74
  generated_text: completion.text,
75
75
  };
76
76
  }
77
- throw new InferenceOutputError("Expected Together text generation response format");
77
+ throw new InferenceClientProviderOutputError("Received malformed response from Together text generation API");
78
78
  }
79
79
  }
80
80
 
@@ -113,6 +113,6 @@ export class TogetherTextToImageTask extends TaskProviderHelper implements TextT
113
113
  return fetch(`data:image/jpeg;base64,${base64Data}`).then((res) => res.blob());
114
114
  }
115
115
 
116
- throw new InferenceOutputError("Expected Together text-to-image response format");
116
+ throw new InferenceClientProviderOutputError("Received malformed response from Together text-to-image API");
117
117
  }
118
118
  }
@@ -1,10 +1,10 @@
1
1
  import type { AutomaticSpeechRecognitionInput, AutomaticSpeechRecognitionOutput } from "@huggingface/tasks";
2
2
  import { resolveProvider } from "../../lib/getInferenceProviderMapping.js";
3
3
  import { getProviderHelper } from "../../lib/getProviderHelper.js";
4
- import { InferenceOutputError } from "../../lib/InferenceOutputError.js";
5
4
  import type { BaseArgs, Options } from "../../types.js";
6
5
  import { innerRequest } from "../../utils/request.js";
7
6
  import type { LegacyAudioInput } from "./utils.js";
7
+ import { InferenceClientProviderOutputError } from "../../errors.js";
8
8
 
9
9
  export type AutomaticSpeechRecognitionArgs = BaseArgs & (AutomaticSpeechRecognitionInput | LegacyAudioInput);
10
10
  /**
@@ -24,7 +24,7 @@ export async function automaticSpeechRecognition(
24
24
  });
25
25
  const isValidOutput = typeof res?.text === "string";
26
26
  if (!isValidOutput) {
27
- throw new InferenceOutputError("Expected {text: string}");
27
+ throw new InferenceClientProviderOutputError("Received malformed response from automatic-speech-recognition API");
28
28
  }
29
29
  return providerHelper.getResponse(res);
30
30
  }
@@ -3,7 +3,7 @@ import { resolveProvider } from "../../lib/getInferenceProviderMapping.js";
3
3
  import { getProviderHelper } from "../../lib/getProviderHelper.js";
4
4
  import { makeRequestOptions } from "../../lib/makeRequestOptions.js";
5
5
  import type { FalAiQueueOutput } from "../../providers/fal-ai.js";
6
- import type { NovitaOutput } from "../../providers/novita.js";
6
+ import type { NovitaAsyncAPIOutput } from "../../providers/novita.js";
7
7
  import type { ReplicateOutput } from "../../providers/replicate.js";
8
8
  import type { BaseArgs, Options } from "../../types.js";
9
9
  import { innerRequest } from "../../utils/request.js";
@@ -15,7 +15,7 @@ export type TextToVideoOutput = Blob;
15
15
  export async function textToVideo(args: TextToVideoArgs, options?: Options): Promise<TextToVideoOutput> {
16
16
  const provider = await resolveProvider(args.provider, args.model, args.endpointUrl);
17
17
  const providerHelper = getProviderHelper(provider, "text-to-video");
18
- const { data: response } = await innerRequest<FalAiQueueOutput | ReplicateOutput | NovitaOutput>(
18
+ const { data: response } = await innerRequest<FalAiQueueOutput | ReplicateOutput | NovitaAsyncAPIOutput>(
19
19
  args,
20
20
  providerHelper,
21
21
  {
@@ -3,6 +3,8 @@ import { makeRequestOptions } from "../lib/makeRequestOptions.js";
3
3
  import type { InferenceTask, Options, RequestArgs } from "../types.js";
4
4
  import type { EventSourceMessage } from "../vendor/fetch-event-source/parse.js";
5
5
  import { getLines, getMessages } from "../vendor/fetch-event-source/parse.js";
6
+ import { InferenceClientProviderApiError } from "../errors.js";
7
+ import type { JsonObject } from "../vendor/type-fest/basic.js";
6
8
 
7
9
  export interface ResponseWrapper<T> {
8
10
  data: T;
@@ -12,6 +14,17 @@ export interface ResponseWrapper<T> {
12
14
  };
13
15
  }
14
16
 
17
+ function requestArgsToJson(args: RequestArgs): JsonObject {
18
+ // Convert the entire args object to a JSON-serializable format
19
+ const argsWithData = args as RequestArgs & { data?: Blob | ArrayBuffer };
20
+ return JSON.parse(
21
+ JSON.stringify({
22
+ ...argsWithData,
23
+ data: argsWithData.data ? "[Blob or ArrayBuffer]" : null,
24
+ })
25
+ ) as JsonObject;
26
+ }
27
+
15
28
  /**
16
29
  * Primitive to make custom calls to the inference provider
17
30
  */
@@ -39,18 +52,54 @@ export async function innerRequest<T>(
39
52
  if (["application/json", "application/problem+json"].some((ct) => contentType?.startsWith(ct))) {
40
53
  const output = await response.json();
41
54
  if ([400, 422, 404, 500].includes(response.status) && options?.chatCompletion) {
42
- throw new Error(
43
- `Server ${args.model} does not seem to support chat completion. Error: ${JSON.stringify(output.error)}`
55
+ throw new InferenceClientProviderApiError(
56
+ `Provider ${args.provider} does not seem to support chat completion for model ${
57
+ args.model
58
+ } . Error: ${JSON.stringify(output.error)}`,
59
+ {
60
+ url,
61
+ method: info.method ?? "GET",
62
+ headers: info.headers as Record<string, string>,
63
+ body: requestArgsToJson(args),
64
+ },
65
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
44
66
  );
45
67
  }
46
- if (output.error || output.detail) {
47
- throw new Error(JSON.stringify(output.error ?? output.detail));
68
+ if (typeof output.error === "string" || typeof output.detail === "string") {
69
+ throw new InferenceClientProviderApiError(
70
+ `Failed to perform inference: ${output.error ?? output.detail}`,
71
+ {
72
+ url,
73
+ method: info.method ?? "GET",
74
+ headers: info.headers as Record<string, string>,
75
+ body: requestArgsToJson(args),
76
+ },
77
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
78
+ );
48
79
  } else {
49
- throw new Error(output);
80
+ throw new InferenceClientProviderApiError(
81
+ `Failed to perform inference: an HTTP error occurred when requesting the provider.`,
82
+ {
83
+ url,
84
+ method: info.method ?? "GET",
85
+ headers: info.headers as Record<string, string>,
86
+ body: requestArgsToJson(args),
87
+ },
88
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
89
+ );
50
90
  }
51
91
  }
52
92
  const message = contentType?.startsWith("text/plain;") ? await response.text() : undefined;
53
- throw new Error(message ?? "An error occurred while fetching the blob");
93
+ throw new InferenceClientProviderApiError(
94
+ `Failed to perform inference: ${message ?? "an HTTP error occurred when requesting the provider"}`,
95
+ {
96
+ url,
97
+ method: info.method ?? "GET",
98
+ headers: info.headers as Record<string, string>,
99
+ body: requestArgsToJson(args),
100
+ },
101
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: message ?? "" }
102
+ );
54
103
  }
55
104
 
56
105
  if (response.headers.get("Content-Type")?.startsWith("application/json")) {
@@ -85,26 +134,81 @@ export async function* innerStreamingRequest<T>(
85
134
  if (response.headers.get("Content-Type")?.startsWith("application/json")) {
86
135
  const output = await response.json();
87
136
  if ([400, 422, 404, 500].includes(response.status) && options?.chatCompletion) {
88
- throw new Error(`Server ${args.model} does not seem to support chat completion. Error: ${output.error}`);
137
+ throw new InferenceClientProviderApiError(
138
+ `Provider ${args.provider} does not seem to support chat completion for model ${
139
+ args.model
140
+ } . Error: ${JSON.stringify(output.error)}`,
141
+ {
142
+ url,
143
+ method: info.method ?? "GET",
144
+ headers: info.headers as Record<string, string>,
145
+ body: requestArgsToJson(args),
146
+ },
147
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
148
+ );
89
149
  }
90
150
  if (typeof output.error === "string") {
91
- throw new Error(output.error);
151
+ throw new InferenceClientProviderApiError(
152
+ `Failed to perform inference: ${output.error}`,
153
+ {
154
+ url,
155
+ method: info.method ?? "GET",
156
+ headers: info.headers as Record<string, string>,
157
+ body: requestArgsToJson(args),
158
+ },
159
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
160
+ );
92
161
  }
93
162
  if (output.error && "message" in output.error && typeof output.error.message === "string") {
94
163
  /// OpenAI errors
95
- throw new Error(output.error.message);
164
+ throw new InferenceClientProviderApiError(
165
+ `Failed to perform inference: ${output.error.message}`,
166
+ {
167
+ url,
168
+ method: info.method ?? "GET",
169
+ headers: info.headers as Record<string, string>,
170
+ body: requestArgsToJson(args),
171
+ },
172
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
173
+ );
96
174
  }
97
175
  // Sambanova errors
98
176
  if (typeof output.message === "string") {
99
- throw new Error(output.message);
177
+ throw new InferenceClientProviderApiError(
178
+ `Failed to perform inference: ${output.message}`,
179
+ {
180
+ url,
181
+ method: info.method ?? "GET",
182
+ headers: info.headers as Record<string, string>,
183
+ body: requestArgsToJson(args),
184
+ },
185
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: output }
186
+ );
100
187
  }
101
188
  }
102
189
 
103
- throw new Error(`Server response contains error: ${response.status}`);
190
+ throw new InferenceClientProviderApiError(
191
+ `Failed to perform inference: an HTTP error occurred when requesting the provider.`,
192
+ {
193
+ url,
194
+ method: info.method ?? "GET",
195
+ headers: info.headers as Record<string, string>,
196
+ body: requestArgsToJson(args),
197
+ },
198
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: "" }
199
+ );
104
200
  }
105
201
  if (!response.headers.get("content-type")?.startsWith("text/event-stream")) {
106
- throw new Error(
107
- `Server does not support event stream content type, it returned ` + response.headers.get("content-type")
202
+ throw new InferenceClientProviderApiError(
203
+ `Failed to perform inference: server does not support event stream content type, it returned ` +
204
+ response.headers.get("content-type"),
205
+ {
206
+ url,
207
+ method: info.method ?? "GET",
208
+ headers: info.headers as Record<string, string>,
209
+ body: requestArgsToJson(args),
210
+ },
211
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: "" }
108
212
  );
109
213
  }
110
214
 
@@ -151,7 +255,16 @@ export async function* innerStreamingRequest<T>(
151
255
  typeof data.error.message === "string"
152
256
  ? data.error.message
153
257
  : JSON.stringify(data.error);
154
- throw new Error(`Error forwarded from backend: ` + errorStr);
258
+ throw new InferenceClientProviderApiError(
259
+ `Failed to perform inference: an occurred while streaming the response: ${errorStr}`,
260
+ {
261
+ url,
262
+ method: info.method ?? "GET",
263
+ headers: info.headers as Record<string, string>,
264
+ body: requestArgsToJson(args),
265
+ },
266
+ { requestId: response.headers.get("x-request-id") ?? "", status: response.status, body: data }
267
+ );
155
268
  }
156
269
  yield data as T;
157
270
  }
@@ -0,0 +1,31 @@
1
+ /**
2
+ Matches a JSON object.
3
+
4
+ This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`.
5
+
6
+ @category JSON
7
+ */
8
+ export type JsonObject = { [Key in string]: JsonValue } & { [Key in string]?: JsonValue | undefined };
9
+
10
+ /**
11
+ Matches a JSON array.
12
+
13
+ @category JSON
14
+ */
15
+ export type JsonArray = JsonValue[] | readonly JsonValue[];
16
+
17
+ /**
18
+ Matches any valid JSON primitive value.
19
+
20
+ @category JSON
21
+ */
22
+ export type JsonPrimitive = string | number | boolean | null;
23
+
24
+ /**
25
+ Matches any valid JSON value.
26
+
27
+ @see `Jsonify` if you need to transform a type to one that is assignable to `JsonValue`.
28
+
29
+ @category JSON
30
+ */
31
+ export type JsonValue = JsonPrimitive | JsonObject | JsonArray;