Skip to content

Commit 762207a

Browse files
committed
✨ Support for Featherless.ai as inference provider.
1 parent e0de008 commit 762207a

File tree

8 files changed

+124
-3
lines changed

8 files changed

+124
-3
lines changed

packages/inference/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ You can send inference requests to third-party providers with the inference clie
4848

4949
Currently, we support the following providers:
5050
- [Fal.ai](https://fal.ai)
51+
- [Featherless](https://featherless.ai)
5152
- [Fireworks AI](https://fireworks.ai)
5253
- [Hyperbolic](https://hyperbolic.xyz)
5354
- [Nebius](https://studio.nebius.ai)
@@ -76,6 +77,7 @@ When authenticated with a third-party provider key, the request is made directly
7677

7778
Only a subset of models are supported when requesting third-party providers. You can check the list of supported models per pipeline tasks here:
7879
- [Fal.ai supported models](https://huggingface.co/api/partners/fal-ai/models)
80+
- [Featherless supported models](https://huggingface.co/api/partners/featherless-ai/models)
7981
- [Fireworks AI supported models](https://huggingface.co/api/partners/fireworks-ai/models)
8082
- [Hyperbolic supported models](https://huggingface.co/api/partners/hyperbolic/models)
8183
- [Nebius supported models](https://huggingface.co/api/partners/nebius/models)

packages/inference/src/lib/makeRequestOptions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BLACK_FOREST_LABS_CONFIG } from "../providers/black-forest-labs";
33
import { CEREBRAS_CONFIG } from "../providers/cerebras";
44
import { COHERE_CONFIG } from "../providers/cohere";
55
import { FAL_AI_CONFIG } from "../providers/fal-ai";
6+
import { FEATHERLESS_AI_CONFIG } from "../providers/featherless-ai";
67
import { FIREWORKS_AI_CONFIG } from "../providers/fireworks-ai";
78
import { HF_INFERENCE_CONFIG } from "../providers/hf-inference";
89
import { HYPERBOLIC_CONFIG } from "../providers/hyperbolic";
@@ -33,6 +34,7 @@ const providerConfigs: Record<InferenceProvider, ProviderConfig> = {
3334
cerebras: CEREBRAS_CONFIG,
3435
cohere: COHERE_CONFIG,
3536
"fal-ai": FAL_AI_CONFIG,
37+
"featherless-ai": FEATHERLESS_AI_CONFIG,
3638
"fireworks-ai": FIREWORKS_AI_CONFIG,
3739
"hf-inference": HF_INFERENCE_CONFIG,
3840
hyperbolic: HYPERBOLIC_CONFIG,

packages/inference/src/providers/consts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const HARDCODED_MODEL_ID_MAPPING: Record<InferenceProvider, Record<ModelI
2020
cerebras: {},
2121
cohere: {},
2222
"fal-ai": {},
23+
"featherless-ai": {},
2324
"fireworks-ai": {},
2425
"hf-inference": {},
2526
hyperbolic: {},
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* See the registered mapping of HF model ID => Featherless model ID here:
3+
*
4+
* https://huggingface.co/api/partners/featherless/models
5+
*
6+
* This is a publicly available mapping.
7+
*
8+
* If you want to try to run inference for a new model locally before it's registered on huggingface.co,
9+
* you can add it to the dictionary "HARDCODED_MODEL_ID_MAPPING" in consts.ts, for dev purposes.
10+
*
11+
* - If you work at Featherless and want to update this mapping, please use the model mapping API we provide on huggingface.co
12+
* - If you're a community member and want to add a new supported HF model to Featherless, please open an issue on the present repo
13+
* and we will tag Featherless team members.
14+
*
15+
* Thanks!
16+
*/
17+
import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types";
18+
19+
const FEATHERLESS_API_BASE_URL = "https://api.featherless.ai";
20+
21+
const makeBody = (params: BodyParams): Record<string, unknown> => {
22+
const { inputs, parameters, ...args } = params.args;
23+
24+
if (inputs) {
25+
args.prompt = inputs;
26+
}
27+
28+
return {
29+
...args,
30+
...(parameters as object),
31+
model: params.model,
32+
};
33+
};
34+
35+
const makeHeaders = (params: HeaderParams): Record<string, string> => {
36+
return { Authorization: `Bearer ${params.accessToken}` };
37+
};
38+
39+
const makeUrl = (params: UrlParams): string => {
40+
if (params.chatCompletion) {
41+
return `${params.baseUrl}/v1/chat/completions`;
42+
}
43+
return `${params.baseUrl}/v1/completions`;
44+
};
45+
46+
export const FEATHERLESS_AI_CONFIG: ProviderConfig = {
47+
baseUrl: FEATHERLESS_API_BASE_URL,
48+
makeBody,
49+
makeHeaders,
50+
makeUrl,
51+
};

packages/inference/src/tasks/nlp/textGeneration.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { omit } from "../../utils/omit";
1212

1313
export type { TextGenerationInput, TextGenerationOutput };
1414

15-
interface TogeteherTextCompletionOutput extends Omit<ChatCompletionOutput, "choices"> {
15+
interface OpenAICompatibleTextCompletion extends Omit<ChatCompletionOutput, "choices"> {
1616
choices: Array<{
1717
text: string;
1818
finish_reason: TextGenerationOutputFinishReason;
@@ -35,9 +35,9 @@ export async function textGeneration(
3535
args: BaseArgs & TextGenerationInput,
3636
options?: Options
3737
): Promise<TextGenerationOutput> {
38-
if (args.provider === "together") {
38+
if (args.provider === "together" || args.provider === "featherless-ai") {
3939
args.prompt = args.inputs;
40-
const raw = await request<TogeteherTextCompletionOutput>(args, {
40+
const raw = await request<OpenAICompatibleTextCompletion>(args, {
4141
...options,
4242
task: "text-generation",
4343
});

packages/inference/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const INFERENCE_PROVIDERS = [
3333
"cerebras",
3434
"cohere",
3535
"fal-ai",
36+
"featherless-ai",
3637
"fireworks-ai",
3738
"hf-inference",
3839
"hyperbolic",

packages/inference/test/InferenceClient.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,69 @@ describe.concurrent("InferenceClient", () => {
884884
TIMEOUT
885885
);
886886

887+
describe.concurrent(
888+
"Featherless",
889+
() => {
890+
HARDCODED_MODEL_ID_MAPPING['featherless-ai'] = {
891+
"meta-llama/Llama-3.1-8B": "meta-llama/Meta-Llama-3.1-8B",
892+
"meta-llama/Llama-3.1-8B-Instruct": "meta-llama/Meta-Llama-3.1-8B-Instruct",
893+
};
894+
895+
it("chatCompletion", async () => {
896+
const res = await chatCompletion({
897+
accessToken: env.HF_FEATHERLESS_KEY ?? "dummy",
898+
model: "meta-llama/Llama-3.1-8B-Instruct",
899+
provider: "featherless-ai",
900+
messages: [{ role: "user", content: "Complete this sentence with words, one plus one is equal " }],
901+
temperature: 0.1,
902+
});
903+
904+
expect(res).toBeDefined();
905+
expect(res.choices).toBeDefined();
906+
expect(res.choices?.length).toBeGreaterThan(0);
907+
908+
if (res.choices && res.choices.length > 0) {
909+
const completion = res.choices[0].message?.content;
910+
expect(completion).toBeDefined();
911+
expect(typeof completion).toBe("string");
912+
expect(completion).toContain("two");
913+
}
914+
});
915+
916+
it("chatCompletion stream", async () => {
917+
const stream = chatCompletionStream({
918+
accessToken: env.HF_FEATHERLESS_KEY ?? "dummy",
919+
model: "meta-llama/Llama-3.1-8B-Instruct",
920+
provider: "featherless-ai",
921+
messages: [{ role: "user", content: "Complete the equation 1 + 1 = , just the answer" }],
922+
}) as AsyncGenerator<ChatCompletionStreamOutput>;
923+
let out = "";
924+
for await (const chunk of stream) {
925+
if (chunk.choices && chunk.choices.length > 0) {
926+
out += chunk.choices[0].delta.content;
927+
}
928+
}
929+
expect(out).toContain("2");
930+
});
931+
932+
it("textGeneration", async () => {
933+
const res = await textGeneration({
934+
accessToken: env.HF_FEATHERLESS_KEY ?? "dummy",
935+
model: "meta-llama/Llama-3.1-8B",
936+
provider: "featherless-ai",
937+
inputs: "Paris is",
938+
parameters: {
939+
temperature: 0,
940+
top_p: 0.01,
941+
max_tokens: 10,
942+
},
943+
});
944+
expect(res).toMatchObject({ generated_text: " a city of romance, art, and culture." });
945+
});
946+
},
947+
TIMEOUT
948+
);
949+
887950
describe.concurrent(
888951
"Replicate",
889952
() => {

packages/tasks/src/inference-providers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const INFERENCE_PROVIDERS = [
44
"cerebras",
55
"cohere",
66
"fal-ai",
7+
"featherless-ai",
78
"fireworks-ai",
89
"hf-inference",
910
"hyperbolic",

0 commit comments

Comments
 (0)