@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
126 lines (125 loc) • 5.03 kB
JavaScript
import { openai } from "@ai-sdk/openai";
import { streamText, Output } from "ai";
import { AIProviderName } from "../core/types.js";
import { BaseProvider } from "../core/baseProvider.js";
import { logger } from "../utils/logger.js";
import { createTimeoutController, TimeoutError, getDefaultTimeout, } from "../utils/timeout.js";
import { DEFAULT_MAX_TOKENS } from "../core/constants.js";
import { validateApiKey, createOpenAIConfig, getProviderModel, } from "../utils/providerConfig.js";
import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
// Configuration helpers - now using consolidated utility
const getOpenAIApiKey = () => {
return validateApiKey(createOpenAIConfig());
};
const getOpenAIModel = () => {
return getProviderModel("OPENAI_MODEL", "gpt-4o");
};
/**
* OpenAI Provider v2 - BaseProvider Implementation
* Migrated to use factory pattern with exact Google AI provider pattern
*/
export class OpenAIProvider extends BaseProvider {
model;
constructor(modelName) {
super(modelName, AIProviderName.OPENAI);
// Set OpenAI API key as environment variable (required by @ai-sdk/openai)
process.env.OPENAI_API_KEY = getOpenAIApiKey();
// Initialize model
this.model = openai(this.modelName);
logger.debug("OpenAIProviderV2 initialized", {
model: this.modelName,
provider: this.providerName,
});
}
// ===================
// ABSTRACT METHOD IMPLEMENTATIONS
// ===================
getProviderName() {
return AIProviderName.OPENAI;
}
getDefaultModel() {
return getOpenAIModel();
}
/**
* Returns the Vercel AI SDK model instance for OpenAI
*/
getAISDKModel() {
return this.model;
}
handleProviderError(error) {
if (error instanceof TimeoutError) {
return new Error(`OpenAI request timed out: ${error.message}`);
}
const errorObj = error;
const message = errorObj?.message && typeof errorObj.message === "string"
? errorObj.message
: "Unknown error";
if (message.includes("API_KEY_INVALID") ||
message.includes("Invalid API key")) {
return new Error("Invalid OpenAI API key. Please check your OPENAI_API_KEY environment variable.");
}
if (message.includes("rate limit")) {
return new Error("OpenAI rate limit exceeded. Please try again later.");
}
return new Error(`OpenAI error: ${message}`);
}
/**
* executeGenerate method removed - generation is now handled by BaseProvider.
* For details on the changes and migration steps, refer to the BaseProvider documentation
* and the migration guide in the project repository.
*/
async executeStream(options, analysisSchema) {
this.validateStreamOptions(options);
const startTime = Date.now();
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 };
}
};
// Create analytics promise that resolves after stream completion
const analyticsPromise = streamAnalyticsCollector.createAnalytics(this.providerName, this.modelName, result, Date.now() - startTime, {
requestId: `openai-stream-${Date.now()}`,
streamingMode: true,
});
return {
stream: transformedStream(),
provider: this.providerName,
model: this.modelName,
analytics: analyticsPromise,
metadata: {
startTime,
streamId: `openai-${Date.now()}`,
},
};
}
catch (error) {
timeoutController?.cleanup();
throw this.handleProviderError(error);
}
}
// ===================
// 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 OpenAIProvider;