diff --git a/app/components/Logo/HuggingFace.vue b/app/components/Logo/HuggingFace.vue
new file mode 100644
index 0000000..4737600
--- /dev/null
+++ b/app/components/Logo/HuggingFace.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
diff --git a/app/components/Logo/Poolside.vue b/app/components/Logo/Poolside.vue
new file mode 100644
index 0000000..060cde5
--- /dev/null
+++ b/app/components/Logo/Poolside.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/components/Logo/Tencent.vue b/app/components/Logo/Tencent.vue
new file mode 100644
index 0000000..3b2ce58
--- /dev/null
+++ b/app/components/Logo/Tencent.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/app/utils/model-mapping.ts b/app/utils/model-mapping.ts
index 7219c82..436361f 100644
--- a/app/utils/model-mapping.ts
+++ b/app/utils/model-mapping.ts
@@ -52,6 +52,9 @@ import {
LogoInflection,
LogoVllm,
LogoClosedRouter,
+ LogoPoolside,
+ LogoTencent,
+ LogoHuggingFace,
} from '#components';
import { markRaw } from 'vue';
@@ -161,7 +164,7 @@ const MODEL_MAPPINGS: ModelConfig[] = [
},
{
Icon: markRaw(LogoZAI),
- keywords: [/^glm-4/, /\/glm-4/, /zai-/, /-glm-4/, /glm-\d/]
+ keywords: [/zai-/, /(^|\/|-)?glm-?\d/]
},
{
Icon: markRaw(LogoGLMV),
@@ -314,6 +317,14 @@ const MODEL_MAPPINGS: ModelConfig[] = [
{
Icon: markRaw(LogoInflection),
keywords: [/inflection-/, /^inflection\//]
+ },
+ {
+ Icon: markRaw(LogoPoolside),
+ keywords: [/poolside\//, /laguna/]
+ },
+ {
+ Icon: markRaw(LogoTencent),
+ keywords: [/tencent\//, /hy/],
}
];
@@ -324,7 +335,7 @@ export const providerIcons: Record = {
azure: null,
anthropic: markRaw(LogoAnthropic),
cohere: markRaw(LogoCohere),
- huggingface: null,
+ huggingface: markRaw(LogoHuggingFace),
openrouter: markRaw(LogoOpenrouter),
cerebras: markRaw(LogoCerebras),
longcat: markRaw(LogoLongCat),
diff --git a/bun.lock b/bun.lock
index a22c872..93e0838 100644
--- a/bun.lock
+++ b/bun.lock
@@ -9,6 +9,7 @@
"@ai-sdk/cerebras": "^2.0.45",
"@ai-sdk/cohere": "^3.0.30",
"@ai-sdk/google": "^3.0.61",
+ "@ai-sdk/huggingface": "^1.0.43",
"@ai-sdk/mistral": "^3.0.30",
"@ai-sdk/openai": "^3.0.52",
"@ai-sdk/openai-compatible": "^2.0.41",
@@ -30,7 +31,7 @@
"comlink": "^4.4.2",
"drizzle-orm": "^1.0.0-beta.21",
"glob": "^13.0.6",
- "longcat-ai-sdk-provider": "^0.0.4",
+ "longcat-ai-sdk-provider": "^0.0.5",
"nanoid": "^5.1.7",
"nuxt": "^4.4.2",
"pg": "^8.20.0",
@@ -80,6 +81,8 @@
"@ai-sdk/google": ["@ai-sdk/google@3.0.61", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-jEKU1Mjcy5CoicejdJQIzM0ntYwyXR8vtYgAZYriKaOuLAiAhiiU538++fGU3CC9HJH/mL1OfsCwMM3gFiCNsw=="],
+ "@ai-sdk/huggingface": ["@ai-sdk/huggingface@1.0.43", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-bEHZNmQNabbs7zYjRa7e0Hz1RFiVwm/hjfZ2YFwTFsxC0WmPSSvjyG5SqRM8DApbSC2EtGP5K/zO2IKEXZrYyQ=="],
+
"@ai-sdk/mistral": ["@ai-sdk/mistral@3.0.30", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-+j4IXRSk9E661cFSafmIr+XHOzwjFagawwzMOlSqwL6U4Sq4PCFLDF+oHbX5NUqNjUL7FD1zi/9lBIfa41pUvw=="],
"@ai-sdk/openai": ["@ai-sdk/openai@3.0.52", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4Rr8NCGmfWTz6DCUvixn9UmyZcMatiHn0zWoMzI3JCUe9R1P/vsPOpCBALKoSzVYOjyJnhtnVIbfUKujcS39uw=="],
@@ -1778,7 +1781,7 @@
"lodash.uniq": ["lodash.uniq@4.5.0", "", {}, "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="],
- "longcat-ai-sdk-provider": ["longcat-ai-sdk-provider@0.0.4", "", { "dependencies": { "@ai-sdk/openai-compatible": "^2.0.37", "@ai-sdk/provider": "^3.0.8", "@ai-sdk/provider-utils": "^4.0.21" }, "peerDependencies": { "ai": ">=6.0.0" } }, "sha512-cAyxpYZIO9jRq7UJCt6tPqoBXUpIvKsvWJsJF1pMtRBGxm6SF96rgHDRupxpA5XX4ODqDo7LRE1hs3viEcLxoA=="],
+ "longcat-ai-sdk-provider": ["longcat-ai-sdk-provider@0.0.5", "", { "dependencies": { "@ai-sdk/openai-compatible": "^2.0.37", "@ai-sdk/provider": "^3.0.8", "@ai-sdk/provider-utils": "^4.0.21" }, "peerDependencies": { "ai": ">=6.0.0" } }, "sha512-VbuhUuJNXnjoRYnpKBi3TSqFsHJaRRlzjFC+Rv4cxbzgHl6KTcohNeVvgbB95p49lMl4kGH6I/VxgdPOSkAi8A=="],
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
@@ -2862,10 +2865,6 @@
"listhen/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
- "longcat-ai-sdk-provider/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.37", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-+POSFVcgiu47BK64dhsI6OpcDC0/VAE2ZSaXdXGNNhpC/ava++uSRJYks0k2bpfY0wwCTgpAWZsXn/dG2Yppiw=="],
-
- "longcat-ai-sdk-provider/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
-
"magic-regexp/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"magicast/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
diff --git a/package.json b/package.json
index c6134e5..d669c72 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@ai-sdk/cerebras": "^2.0.45",
"@ai-sdk/cohere": "^3.0.30",
"@ai-sdk/google": "^3.0.61",
+ "@ai-sdk/huggingface": "^1.0.43",
"@ai-sdk/mistral": "^3.0.30",
"@ai-sdk/openai": "^3.0.52",
"@ai-sdk/openai-compatible": "^2.0.41",
@@ -35,7 +36,7 @@
"comlink": "^4.4.2",
"drizzle-orm": "^1.0.0-beta.21",
"glob": "^13.0.6",
- "longcat-ai-sdk-provider": "^0.0.4",
+ "longcat-ai-sdk-provider": "^0.0.5",
"nanoid": "^5.1.7",
"nuxt": "^4.4.2",
"pg": "^8.20.0",
diff --git a/server/utils/providers/huggingface.ts b/server/utils/providers/huggingface.ts
new file mode 100644
index 0000000..07e40b9
--- /dev/null
+++ b/server/utils/providers/huggingface.ts
@@ -0,0 +1,51 @@
+import { createHuggingFace } from '@ai-sdk/huggingface';
+import { GatewayFetchError } from '~~/server/utils/ai-provider';
+import { Err, Ok } from '~~/types/result';
+import type { ProviderModule } from '.';
+import { getModelData } from './helpers';
+
+export default {
+ id: 'huggingface',
+ baseUrl: 'https://router.huggingface.co/v1',
+ modelsEndpoint: null,
+
+ createGateway({ apiKey, baseURL }) {
+ if (apiKey === undefined) {
+ return Err(GatewayFetchError.NoProviderApiKey);
+ }
+
+ return Ok({
+ gateway: createHuggingFace({ apiKey, baseURL }),
+ streamTransformer: undefined,
+ textTransformer: undefined,
+ });
+ },
+
+ getAuthHeaders(apiKey) {
+ return apiKey ? { Authorization: `Bearer ${apiKey}` } : {};
+ },
+
+ async fetchModels({ baseURL, apiKey, modelsDevData }) {
+ const res = await fetch(
+ 'https://huggingface.co/api/models?pipeline_tag=text-generation&sort=downloads',
+ {
+ method: 'GET',
+ headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
+ },
+ );
+ const data = await res.json();
+
+ if (!res.ok) {
+ throw createError({ statusCode: res.status, message: JSON.stringify(data) });
+ }
+
+ return data
+ .filter((model: any) => model.tags?.includes('text-generation-inference'))
+ .map((model: any) => ({
+ ...getModelData(model.id, 'huggingface', modelsDevData),
+ id: model.id,
+ name: model.id,
+ releasedAt: model.createdAt,
+ }));
+ },
+} satisfies ProviderModule;
diff --git a/server/utils/providers/index.ts b/server/utils/providers/index.ts
index ab673f7..a1e80b7 100644
--- a/server/utils/providers/index.ts
+++ b/server/utils/providers/index.ts
@@ -12,6 +12,7 @@ import nvidia from './nvidia';
import xiaomi from './xiaomi';
import openai from './openai';
import anthropic from './anthropic';
+import huggingface from './huggingface';
import type { Result } from '~~/types/result';
import type { Gateway, GatewayFetchError } from '~~/server/utils/ai-provider';
import type { Model as ModelDrizzle } from '~/composables/useModels';
@@ -65,6 +66,7 @@ const providers = [
xiaomi,
openai,
anthropic,
+ huggingface,
];
type ProviderId = typeof providers[number]['id'];