Feat/add.azure.and.other.providers (#607)
* fix: claude-4 not having the right max_tokens * feat: add bedrock support * chore: fix package-lock.json * fix: rename baseUrl to baseURL * feat: add azure support * fix: final touches of azure integration * feat: add google vertex provider * chore: fix tests and refactor task-manager.test.js * chore: move task 92 to 94
This commit is contained in:
@@ -1,199 +1,39 @@
|
||||
import { createOpenAI } from '@ai-sdk/openai'; // Using openai provider from Vercel AI SDK
|
||||
import { generateObject, generateText } from 'ai'; // Import necessary functions from 'ai'
|
||||
import { log } from '../../scripts/modules/utils.js';
|
||||
|
||||
function getClient(apiKey, baseUrl) {
|
||||
if (!apiKey) {
|
||||
throw new Error('OpenAI API key is required.');
|
||||
}
|
||||
return createOpenAI({
|
||||
apiKey: apiKey,
|
||||
...(baseUrl && { baseURL: baseUrl })
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates text using OpenAI models via Vercel AI SDK.
|
||||
*
|
||||
* @param {object} params - Parameters including apiKey, modelId, messages, maxTokens, temperature, baseUrl.
|
||||
* @returns {Promise<object>} The generated text content and usage.
|
||||
* @throws {Error} If API call fails.
|
||||
* openai.js
|
||||
* AI provider implementation for OpenAI models using Vercel AI SDK.
|
||||
*/
|
||||
export async function generateOpenAIText(params) {
|
||||
const { apiKey, modelId, messages, maxTokens, temperature, baseUrl } = params;
|
||||
log('debug', `generateOpenAIText called with model: ${modelId}`);
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OpenAI API key is required.');
|
||||
}
|
||||
if (!modelId) {
|
||||
throw new Error('OpenAI Model ID is required.');
|
||||
}
|
||||
if (!messages || !Array.isArray(messages) || messages.length === 0) {
|
||||
throw new Error('Invalid or empty messages array provided for OpenAI.');
|
||||
import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { BaseAIProvider } from './base-provider.js';
|
||||
|
||||
export class OpenAIProvider extends BaseAIProvider {
|
||||
constructor() {
|
||||
super();
|
||||
this.name = 'OpenAI';
|
||||
}
|
||||
|
||||
const openaiClient = getClient(apiKey, baseUrl);
|
||||
/**
|
||||
* Creates and returns an OpenAI client instance.
|
||||
* @param {object} params - Parameters for client initialization
|
||||
* @param {string} params.apiKey - OpenAI API key
|
||||
* @param {string} [params.baseURL] - Optional custom API endpoint
|
||||
* @returns {Function} OpenAI client function
|
||||
* @throws {Error} If API key is missing or initialization fails
|
||||
*/
|
||||
getClient(params) {
|
||||
try {
|
||||
const { apiKey, baseURL } = params;
|
||||
|
||||
try {
|
||||
const result = await generateText({
|
||||
model: openaiClient(modelId),
|
||||
messages,
|
||||
maxTokens,
|
||||
temperature
|
||||
});
|
||||
|
||||
if (!result || !result.text) {
|
||||
log(
|
||||
'warn',
|
||||
'OpenAI generateText response did not contain expected content.',
|
||||
{ result }
|
||||
);
|
||||
throw new Error('Failed to extract content from OpenAI response.');
|
||||
}
|
||||
log(
|
||||
'debug',
|
||||
`OpenAI generateText completed successfully for model: ${modelId}`
|
||||
);
|
||||
return {
|
||||
text: result.text.trim(),
|
||||
usage: {
|
||||
inputTokens: result.usage.promptTokens,
|
||||
outputTokens: result.usage.completionTokens
|
||||
if (!apiKey) {
|
||||
throw new Error('OpenAI API key is required.');
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
log(
|
||||
'error',
|
||||
`Error in generateOpenAIText (Model: ${modelId}): ${error.message}`,
|
||||
{ error }
|
||||
);
|
||||
throw new Error(
|
||||
`OpenAI API error during text generation: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams text using OpenAI models via Vercel AI SDK.
|
||||
*
|
||||
* @param {object} params - Parameters including apiKey, modelId, messages, maxTokens, temperature, baseUrl.
|
||||
* @returns {Promise<ReadableStream>} A readable stream of text deltas.
|
||||
* @throws {Error} If API call fails.
|
||||
*/
|
||||
export async function streamOpenAIText(params) {
|
||||
const { apiKey, modelId, messages, maxTokens, temperature, baseUrl } = params;
|
||||
log('debug', `streamOpenAIText called with model: ${modelId}`);
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OpenAI API key is required.');
|
||||
}
|
||||
if (!modelId) {
|
||||
throw new Error('OpenAI Model ID is required.');
|
||||
}
|
||||
if (!messages || !Array.isArray(messages) || messages.length === 0) {
|
||||
throw new Error(
|
||||
'Invalid or empty messages array provided for OpenAI streaming.'
|
||||
);
|
||||
}
|
||||
|
||||
const openaiClient = getClient(apiKey, baseUrl);
|
||||
|
||||
try {
|
||||
const stream = await openaiClient.chat.stream(messages, {
|
||||
model: modelId,
|
||||
max_tokens: maxTokens,
|
||||
temperature
|
||||
});
|
||||
|
||||
log(
|
||||
'debug',
|
||||
`OpenAI streamText initiated successfully for model: ${modelId}`
|
||||
);
|
||||
return stream;
|
||||
} catch (error) {
|
||||
log(
|
||||
'error',
|
||||
`Error initiating OpenAI stream (Model: ${modelId}): ${error.message}`,
|
||||
{ error }
|
||||
);
|
||||
throw new Error(
|
||||
`OpenAI API error during streaming initiation: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates structured objects using OpenAI models via Vercel AI SDK.
|
||||
*
|
||||
* @param {object} params - Parameters including apiKey, modelId, messages, schema, objectName, maxTokens, temperature, baseUrl.
|
||||
* @returns {Promise<object>} The generated object matching the schema and usage.
|
||||
* @throws {Error} If API call fails or object generation fails.
|
||||
*/
|
||||
export async function generateOpenAIObject(params) {
|
||||
const {
|
||||
apiKey,
|
||||
modelId,
|
||||
messages,
|
||||
schema,
|
||||
objectName,
|
||||
maxTokens,
|
||||
temperature,
|
||||
baseUrl
|
||||
} = params;
|
||||
log(
|
||||
'debug',
|
||||
`generateOpenAIObject called with model: ${modelId}, object: ${objectName}`
|
||||
);
|
||||
|
||||
if (!apiKey) throw new Error('OpenAI API key is required.');
|
||||
if (!modelId) throw new Error('OpenAI Model ID is required.');
|
||||
if (!messages || !Array.isArray(messages) || messages.length === 0)
|
||||
throw new Error('Invalid messages array for OpenAI object generation.');
|
||||
if (!schema)
|
||||
throw new Error('Schema is required for OpenAI object generation.');
|
||||
if (!objectName)
|
||||
throw new Error('Object name is required for OpenAI object generation.');
|
||||
|
||||
const openaiClient = getClient(apiKey, baseUrl);
|
||||
|
||||
try {
|
||||
const result = await generateObject({
|
||||
model: openaiClient(modelId),
|
||||
schema: schema,
|
||||
messages: messages,
|
||||
mode: 'tool',
|
||||
maxTokens: maxTokens,
|
||||
temperature: temperature
|
||||
});
|
||||
|
||||
log(
|
||||
'debug',
|
||||
`OpenAI generateObject completed successfully for model: ${modelId}`
|
||||
);
|
||||
if (!result || typeof result.object === 'undefined') {
|
||||
log(
|
||||
'warn',
|
||||
'OpenAI generateObject response did not contain expected object.',
|
||||
{ result }
|
||||
);
|
||||
throw new Error('Failed to extract object from OpenAI response.');
|
||||
return createOpenAI({
|
||||
apiKey,
|
||||
...(baseURL && { baseURL })
|
||||
});
|
||||
} catch (error) {
|
||||
this.handleError('client initialization', error);
|
||||
}
|
||||
return {
|
||||
object: result.object,
|
||||
usage: {
|
||||
inputTokens: result.usage.promptTokens,
|
||||
outputTokens: result.usage.completionTokens
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
log(
|
||||
'error',
|
||||
`Error in generateOpenAIObject (Model: ${modelId}, Object: ${objectName}): ${error.message}`,
|
||||
{ error }
|
||||
);
|
||||
throw new Error(
|
||||
`OpenAI API error during object generation: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user