@huggingface/inference 3.15.0 → 4.0.1

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 (134) hide show
  1. package/README.md +102 -0
  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 +4 -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 +2 -2
  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.map +1 -1
  30. package/dist/commonjs/providers/novita.js +12 -8
  31. package/dist/commonjs/providers/nscale.d.ts.map +1 -1
  32. package/dist/commonjs/providers/nscale.js +2 -2
  33. package/dist/commonjs/providers/ovhcloud.d.ts.map +1 -1
  34. package/dist/commonjs/providers/ovhcloud.js +2 -2
  35. package/dist/commonjs/providers/providerHelper.js +3 -3
  36. package/dist/commonjs/providers/replicate.js +4 -4
  37. package/dist/commonjs/providers/sambanova.d.ts +16 -0
  38. package/dist/commonjs/providers/sambanova.d.ts.map +1 -1
  39. package/dist/commonjs/providers/sambanova.js +2 -18
  40. package/dist/commonjs/providers/together.d.ts.map +1 -1
  41. package/dist/commonjs/providers/together.js +3 -3
  42. package/dist/commonjs/snippets/getInferenceSnippets.d.ts +2 -1
  43. package/dist/commonjs/snippets/getInferenceSnippets.d.ts.map +1 -1
  44. package/dist/commonjs/snippets/getInferenceSnippets.js +44 -5
  45. package/dist/commonjs/tasks/audio/automaticSpeechRecognition.d.ts.map +1 -1
  46. package/dist/commonjs/tasks/audio/automaticSpeechRecognition.js +2 -2
  47. package/dist/commonjs/utils/request.d.ts.map +1 -1
  48. package/dist/commonjs/utils/request.js +77 -12
  49. package/dist/commonjs/vendor/type-fest/basic.d.ts +33 -0
  50. package/dist/commonjs/vendor/type-fest/basic.d.ts.map +1 -0
  51. package/dist/commonjs/vendor/type-fest/basic.js +2 -0
  52. package/dist/esm/errors.d.ts +46 -0
  53. package/dist/esm/errors.d.ts.map +1 -0
  54. package/dist/esm/errors.js +62 -0
  55. package/dist/esm/index.d.ts +1 -1
  56. package/dist/esm/index.d.ts.map +1 -1
  57. package/dist/esm/index.js +1 -1
  58. package/dist/esm/lib/getInferenceProviderMapping.d.ts.map +1 -1
  59. package/dist/esm/lib/getInferenceProviderMapping.js +27 -16
  60. package/dist/esm/lib/getProviderHelper.d.ts.map +1 -1
  61. package/dist/esm/lib/getProviderHelper.js +4 -3
  62. package/dist/esm/lib/makeRequestOptions.d.ts.map +1 -1
  63. package/dist/esm/lib/makeRequestOptions.js +12 -11
  64. package/dist/esm/package.d.ts +1 -1
  65. package/dist/esm/package.d.ts.map +1 -1
  66. package/dist/esm/package.js +1 -1
  67. package/dist/esm/providers/black-forest-labs.d.ts.map +1 -1
  68. package/dist/esm/providers/black-forest-labs.js +4 -4
  69. package/dist/esm/providers/fal-ai.d.ts.map +1 -1
  70. package/dist/esm/providers/fal-ai.js +29 -17
  71. package/dist/esm/providers/featherless-ai.d.ts.map +1 -1
  72. package/dist/esm/providers/featherless-ai.js +2 -2
  73. package/dist/esm/providers/hf-inference.d.ts.map +1 -1
  74. package/dist/esm/providers/hf-inference.js +27 -30
  75. package/dist/esm/providers/hyperbolic.d.ts.map +1 -1
  76. package/dist/esm/providers/hyperbolic.js +3 -3
  77. package/dist/esm/providers/nebius.d.ts.map +1 -1
  78. package/dist/esm/providers/nebius.js +2 -2
  79. package/dist/esm/providers/novita.d.ts.map +1 -1
  80. package/dist/esm/providers/novita.js +12 -8
  81. package/dist/esm/providers/nscale.d.ts.map +1 -1
  82. package/dist/esm/providers/nscale.js +2 -2
  83. package/dist/esm/providers/ovhcloud.d.ts.map +1 -1
  84. package/dist/esm/providers/ovhcloud.js +2 -2
  85. package/dist/esm/providers/providerHelper.js +3 -3
  86. package/dist/esm/providers/replicate.js +4 -4
  87. package/dist/esm/providers/sambanova.d.ts +16 -0
  88. package/dist/esm/providers/sambanova.d.ts.map +1 -1
  89. package/dist/esm/providers/sambanova.js +2 -18
  90. package/dist/esm/providers/together.d.ts.map +1 -1
  91. package/dist/esm/providers/together.js +3 -3
  92. package/dist/esm/snippets/getInferenceSnippets.d.ts +2 -1
  93. package/dist/esm/snippets/getInferenceSnippets.d.ts.map +1 -1
  94. package/dist/esm/snippets/getInferenceSnippets.js +44 -5
  95. package/dist/esm/tasks/audio/automaticSpeechRecognition.d.ts.map +1 -1
  96. package/dist/esm/tasks/audio/automaticSpeechRecognition.js +2 -2
  97. package/dist/esm/utils/request.d.ts.map +1 -1
  98. package/dist/esm/utils/request.js +77 -12
  99. package/dist/esm/vendor/type-fest/basic.d.ts +33 -0
  100. package/dist/esm/vendor/type-fest/basic.d.ts.map +1 -0
  101. package/dist/esm/vendor/type-fest/basic.js +1 -0
  102. package/package.json +2 -2
  103. package/src/errors.ts +82 -0
  104. package/src/index.ts +1 -1
  105. package/src/lib/getInferenceProviderMapping.ts +42 -22
  106. package/src/lib/getProviderHelper.ts +8 -3
  107. package/src/lib/makeRequestOptions.ts +20 -11
  108. package/src/package.ts +1 -1
  109. package/src/providers/black-forest-labs.ts +14 -4
  110. package/src/providers/fal-ai.ts +59 -23
  111. package/src/providers/featherless-ai.ts +2 -2
  112. package/src/providers/hf-inference.ts +75 -34
  113. package/src/providers/hyperbolic.ts +3 -4
  114. package/src/providers/nebius.ts +2 -2
  115. package/src/providers/novita.ts +30 -8
  116. package/src/providers/nscale.ts +2 -2
  117. package/src/providers/ovhcloud.ts +2 -2
  118. package/src/providers/providerHelper.ts +3 -3
  119. package/src/providers/replicate.ts +4 -4
  120. package/src/providers/sambanova.ts +3 -4
  121. package/src/providers/together.ts +3 -3
  122. package/src/snippets/getInferenceSnippets.ts +69 -7
  123. package/src/tasks/audio/automaticSpeechRecognition.ts +2 -2
  124. package/src/utils/request.ts +127 -14
  125. package/src/vendor/type-fest/basic.ts +31 -0
  126. package/src/vendor/type-fest/license-cc0 +121 -0
  127. package/src/vendor/type-fest/license-mit +9 -0
  128. package/dist/commonjs/lib/InferenceOutputError.d.ts +0 -4
  129. package/dist/commonjs/lib/InferenceOutputError.d.ts.map +0 -1
  130. package/dist/commonjs/lib/InferenceOutputError.js +0 -10
  131. package/dist/esm/lib/InferenceOutputError.d.ts +0 -4
  132. package/dist/esm/lib/InferenceOutputError.d.ts.map +0 -1
  133. package/dist/esm/lib/InferenceOutputError.js +0 -6
  134. package/src/lib/InferenceOutputError.ts +0 -8
@@ -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
  }
@@ -14,7 +14,10 @@ import { makeRequestOptionsFromResolvedModel } from "../lib/makeRequestOptions.j
14
14
  import type { InferenceProviderOrPolicy, InferenceTask, RequestArgs } from "../types.js";
15
15
  import { templates } from "./templates.exported.js";
16
16
 
17
- export type InferenceSnippetOptions = { streaming?: boolean; billTo?: string } & Record<string, unknown>;
17
+ export type InferenceSnippetOptions = { streaming?: boolean; billTo?: string; accessToken?: string } & Record<
18
+ string,
19
+ unknown
20
+ >;
18
21
 
19
22
  const PYTHON_CLIENTS = ["huggingface_hub", "fal_client", "requests", "openai"] as const;
20
23
  const JS_CLIENTS = ["fetch", "huggingface.js", "openai"] as const;
@@ -121,11 +124,12 @@ const HF_JS_METHODS: Partial<Record<WidgetType, string>> = {
121
124
  translation: "translation",
122
125
  };
123
126
 
127
+ const ACCESS_TOKEN_PLACEHOLDER = "<ACCESS_TOKEN>"; // Placeholder to replace with env variable in snippets
128
+
124
129
  // Snippet generators
125
130
  const snippetGenerator = (templateName: string, inputPreparationFn?: InputPreparationFn) => {
126
131
  return (
127
132
  model: ModelDataMinimal,
128
- accessToken: string,
129
133
  provider: InferenceProviderOrPolicy,
130
134
  inferenceProviderMapping?: InferenceProviderModelMapping,
131
135
  opts?: InferenceSnippetOptions
@@ -149,13 +153,15 @@ const snippetGenerator = (templateName: string, inputPreparationFn?: InputPrepar
149
153
  console.error(`Failed to get provider helper for ${provider} (${task})`, e);
150
154
  return [];
151
155
  }
156
+ const accessTokenOrPlaceholder = opts?.accessToken ?? ACCESS_TOKEN_PLACEHOLDER;
157
+
152
158
  /// Prepare inputs + make request
153
159
  const inputs = inputPreparationFn ? inputPreparationFn(model, opts) : { inputs: getModelInputSnippet(model) };
154
160
  const request = makeRequestOptionsFromResolvedModel(
155
161
  providerModelId,
156
162
  providerHelper,
157
163
  {
158
- accessToken,
164
+ accessToken: accessTokenOrPlaceholder,
159
165
  provider,
160
166
  ...inputs,
161
167
  } as RequestArgs,
@@ -180,7 +186,7 @@ const snippetGenerator = (templateName: string, inputPreparationFn?: InputPrepar
180
186
 
181
187
  /// Prepare template injection data
182
188
  const params: TemplateParams = {
183
- accessToken,
189
+ accessToken: accessTokenOrPlaceholder,
184
190
  authorizationHeader: (request.info.headers as Record<string, string>)?.Authorization,
185
191
  baseUrl: removeSuffix(request.url, "/chat/completions"),
186
192
  fullUrl: request.url,
@@ -248,6 +254,11 @@ const snippetGenerator = (templateName: string, inputPreparationFn?: InputPrepar
248
254
  snippet = `${importSection}\n\n${snippet}`;
249
255
  }
250
256
 
257
+ /// Replace access token placeholder
258
+ if (snippet.includes(ACCESS_TOKEN_PLACEHOLDER)) {
259
+ snippet = replaceAccessTokenPlaceholder(snippet, language, provider);
260
+ }
261
+
251
262
  /// Snippet is ready!
252
263
  return { language, client: client as string, content: snippet };
253
264
  })
@@ -299,7 +310,6 @@ const snippets: Partial<
299
310
  PipelineType,
300
311
  (
301
312
  model: ModelDataMinimal,
302
- accessToken: string,
303
313
  provider: InferenceProviderOrPolicy,
304
314
  inferenceProviderMapping?: InferenceProviderModelMapping,
305
315
  opts?: InferenceSnippetOptions
@@ -339,13 +349,12 @@ const snippets: Partial<
339
349
 
340
350
  export function getInferenceSnippets(
341
351
  model: ModelDataMinimal,
342
- accessToken: string,
343
352
  provider: InferenceProviderOrPolicy,
344
353
  inferenceProviderMapping?: InferenceProviderModelMapping,
345
354
  opts?: Record<string, unknown>
346
355
  ): InferenceSnippet[] {
347
356
  return model.pipeline_tag && model.pipeline_tag in snippets
348
- ? snippets[model.pipeline_tag]?.(model, accessToken, provider, inferenceProviderMapping, opts) ?? []
357
+ ? snippets[model.pipeline_tag]?.(model, provider, inferenceProviderMapping, opts) ?? []
349
358
  : [];
350
359
  }
351
360
 
@@ -420,3 +429,56 @@ function indentString(str: string): string {
420
429
  function removeSuffix(str: string, suffix: string) {
421
430
  return str.endsWith(suffix) ? str.slice(0, -suffix.length) : str;
422
431
  }
432
+
433
+ function replaceAccessTokenPlaceholder(
434
+ snippet: string,
435
+ language: InferenceSnippetLanguage,
436
+ provider: InferenceProviderOrPolicy
437
+ ): string {
438
+ // If "opts.accessToken" is not set, the snippets are generated with a placeholder.
439
+ // Once snippets are rendered, we replace the placeholder with code to fetch the access token from an environment variable.
440
+
441
+ // Determine if HF_TOKEN or specific provider token should be used
442
+ const accessTokenEnvVar =
443
+ !snippet.includes("https://") || // no URL provided => using a client => use $HF_TOKEN
444
+ snippet.includes("https://router.huggingface.co") || // explicit routed request => use $HF_TOKEN
445
+ provider == "hf-inference" // hf-inference provider => use $HF_TOKEN
446
+ ? "HF_TOKEN"
447
+ : provider.toUpperCase().replace("-", "_") + "_API_KEY"; // e.g. "REPLICATE_API_KEY"
448
+
449
+ // Replace the placeholder with the env variable
450
+ if (language === "sh") {
451
+ snippet = snippet.replace(
452
+ `'Authorization: Bearer ${ACCESS_TOKEN_PLACEHOLDER}'`,
453
+ `"Authorization: Bearer $${accessTokenEnvVar}"` // e.g. "Authorization: Bearer $HF_TOKEN"
454
+ );
455
+ } else if (language === "python") {
456
+ snippet = "import os\n" + snippet;
457
+ snippet = snippet.replace(
458
+ `"${ACCESS_TOKEN_PLACEHOLDER}"`,
459
+ `os.environ["${accessTokenEnvVar}"]` // e.g. os.environ["HF_TOKEN")
460
+ );
461
+ snippet = snippet.replace(
462
+ `"Bearer ${ACCESS_TOKEN_PLACEHOLDER}"`,
463
+ `f"Bearer {os.environ['${accessTokenEnvVar}']}"` // e.g. f"Bearer {os.environ['HF_TOKEN']}"
464
+ );
465
+ snippet = snippet.replace(
466
+ `"Key ${ACCESS_TOKEN_PLACEHOLDER}"`,
467
+ `f"Key {os.environ['${accessTokenEnvVar}']}"` // e.g. f"Key {os.environ['FAL_AI_API_KEY']}"
468
+ );
469
+ } else if (language === "js") {
470
+ snippet = snippet.replace(
471
+ `"${ACCESS_TOKEN_PLACEHOLDER}"`,
472
+ `process.env.${accessTokenEnvVar}` // e.g. process.env.HF_TOKEN
473
+ );
474
+ snippet = snippet.replace(
475
+ `Authorization: "Bearer ${ACCESS_TOKEN_PLACEHOLDER}",`,
476
+ `Authorization: \`Bearer $\{process.env.${accessTokenEnvVar}}\`,` // e.g. Authorization: `Bearer ${process.env.HF_TOKEN}`,
477
+ );
478
+ snippet = snippet.replace(
479
+ `Authorization: "Key ${ACCESS_TOKEN_PLACEHOLDER}",`,
480
+ `Authorization: \`Key $\{process.env.${accessTokenEnvVar}}\`,` // e.g. Authorization: `Key ${process.env.FAL_AI_API_KEY}`,
481
+ );
482
+ }
483
+ return snippet;
484
+ }
@@ -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,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" || typeof output.message === "string") {
69
+ throw new InferenceClientProviderApiError(
70
+ `Failed to perform inference: ${output.error ?? output.detail ?? output.message}`,
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;