@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and
148 lines (147 loc) • 6.08 kB
JavaScript
import { createOpenAI } from "@ai-sdk/openai";
import { streamText } from "ai";
import { BaseProvider } from "../core/baseProvider.js";
import { logger } from "../utils/logger.js";
import { createTimeoutController, TimeoutError, } from "../utils/timeout.js";
import { DEFAULT_MAX_TOKENS } from "../core/constants.js";
import { validateApiKey, createHuggingFaceConfig, getProviderModel, } from "../utils/providerConfig.js";
// Configuration helpers - now using consolidated utility
const getHuggingFaceApiKey = () => {
return validateApiKey(createHuggingFaceConfig());
};
const getDefaultHuggingFaceModel = () => {
return getProviderModel("HUGGINGFACE_MODEL", "microsoft/DialoGPT-medium");
};
// Note: hasHuggingFaceCredentials now directly imported from consolidated utility
/**
* HuggingFace Provider - BaseProvider Implementation
* Using AI SDK with HuggingFace's OpenAI-compatible endpoint
*/
export class HuggingFaceProvider extends BaseProvider {
model;
constructor(modelName) {
super(modelName, "huggingface");
// Get API key and validate
const apiKey = getHuggingFaceApiKey();
// Create HuggingFace provider using unified router endpoint (2025)
const huggingface = createOpenAI({
apiKey: apiKey,
baseURL: "https://router.huggingface.co/v1",
});
// Initialize model
this.model = huggingface(this.modelName);
logger.debug("HuggingFaceProvider initialized", {
model: this.modelName,
provider: this.providerName,
});
}
// ===================
// ABSTRACT METHOD IMPLEMENTATIONS
// ===================
/**
* HuggingFace models currently don't properly support tool/function calling
*
* **Tested Models & Issues:**
* - microsoft/DialoGPT-medium: Describes tools instead of executing them
* - Most HF models via router endpoint: Function schema passed but not executed
* - Issue: Models treat tool definitions as conversation context rather than executable functions
*
* **Known Limitations:**
* - Tools are visible to model but treated as descriptive text
* - No proper function call response format handling
* - HuggingFace router endpoint doesn't enforce OpenAI-compatible tool execution
*
* @returns false to disable tools by default until proper implementation
*/
supportsTools() {
// IMPLEMENTATION STATUS (2025): HuggingFace tool calling remains limited
//
// Current State:
// - Function calling varies significantly across HF models
// - Many models treat tool schemas as conversation context
// - Requires model-specific implementation per architecture
//
// To Enable Tools:
// 1. Detect model capability via HF model card metadata
// 2. Implement model-specific tool schema formatting
// 3. Add custom response parsing for function call extraction
// 4. Create validation framework for tool parameter handling
// 5. Test extensively with supported models (Code Llama, Llama 3.1+)
//
// Until comprehensive implementation, tools disabled for reliability
return false;
}
// executeGenerate removed - BaseProvider handles all generation with tools
async executeStream(options, analysisSchema) {
this.validateStreamOptions(options);
const timeout = this.getTimeout(options);
const timeoutController = createTimeoutController(timeout, this.providerName, "stream");
try {
const result = await streamText({
model: this.model,
prompt: options.input.text,
system: options.systemPrompt,
temperature: options.temperature,
maxTokens: options.maxTokens || DEFAULT_MAX_TOKENS,
tools: options.tools,
toolChoice: "auto",
abortSignal: timeoutController?.controller.signal,
});
timeoutController?.cleanup();
// Transform stream to match StreamResult interface
const transformedStream = async function* () {
for await (const chunk of result.textStream) {
yield { content: chunk };
}
};
return {
stream: transformedStream(),
provider: this.providerName,
model: this.modelName,
};
}
catch (error) {
timeoutController?.cleanup();
throw this.handleProviderError(error);
}
}
getProviderName() {
return "huggingface";
}
getDefaultModel() {
return getDefaultHuggingFaceModel();
}
/**
* Returns the Vercel AI SDK model instance for HuggingFace
*/
getAISDKModel() {
return this.model;
}
handleProviderError(error) {
if (error instanceof TimeoutError) {
return new Error(`HuggingFace request timed out: ${error.message}`);
}
const errorObj = error;
const message = errorObj?.message && typeof errorObj.message === "string"
? errorObj.message
: "Unknown error";
if (message.includes("API_TOKEN_INVALID") ||
message.includes("Invalid token")) {
return new Error("Invalid HuggingFace API token. Please check your HUGGING_FACE_API_KEY environment variable.");
}
if (message.includes("rate limit")) {
return new Error("HuggingFace rate limit exceeded. Please try again later.");
}
return new Error(`HuggingFace error: ${message}`);
}
// ===================
// PRIVATE VALIDATION METHODS
// ===================
validateStreamOptions(options) {
if (!options.input?.text || options.input.text.trim().length === 0) {
throw new Error("Input text is required and cannot be empty");
}
}
}
// Export for factory registration
export default HuggingFaceProvider;