mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Merge pull request #5 from bayer-int/feature/bayer-mga-provider
Feature/bayer mga provider
This commit is contained in:
commit
198e6c0ec1
@ -19,6 +19,7 @@ import type { IconType } from 'react-icons';
|
||||
type ProviderName =
|
||||
| 'AmazonBedrock'
|
||||
| 'Anthropic'
|
||||
| 'BayerMGA'
|
||||
| 'Cohere'
|
||||
| 'Deepseek'
|
||||
| 'Google'
|
||||
@ -36,6 +37,7 @@ type ProviderName =
|
||||
const PROVIDER_ICONS: Record<ProviderName, IconType> = {
|
||||
AmazonBedrock: SiAmazon,
|
||||
Anthropic: FaBrain,
|
||||
BayerMGA: BsRobot,
|
||||
Cohere: BiChip,
|
||||
Deepseek: BiCodeBlock,
|
||||
Google: SiGoogle,
|
||||
@ -53,6 +55,7 @@ const PROVIDER_ICONS: Record<ProviderName, IconType> = {
|
||||
// Update PROVIDER_DESCRIPTIONS to use the same type
|
||||
const PROVIDER_DESCRIPTIONS: Partial<Record<ProviderName, string>> = {
|
||||
Anthropic: 'Access Claude and other Anthropic models',
|
||||
BayerMGA: 'Connect to Bayer\'s internal AI assistant platform',
|
||||
OpenAI: 'Use GPT-4, GPT-3.5, and other OpenAI models',
|
||||
};
|
||||
|
||||
|
@ -16,11 +16,13 @@ import { useToast } from '~/components/ui/use-toast';
|
||||
type ProviderName =
|
||||
| 'AmazonBedrock'
|
||||
| 'Anthropic'
|
||||
| 'BayerMGA'
|
||||
| 'Cohere'
|
||||
| 'Deepseek'
|
||||
| 'Google'
|
||||
| 'Groq'
|
||||
| 'HuggingFace'
|
||||
| 'Hyperbolic'
|
||||
| 'Mistral'
|
||||
| 'OpenAI'
|
||||
| 'OpenRouter'
|
||||
@ -82,6 +84,14 @@ const PROVIDER_STATUS_URLS: Record<ProviderName, ProviderConfig> = {
|
||||
},
|
||||
testModel: 'claude-3-sonnet-20240229',
|
||||
},
|
||||
BayerMGA: {
|
||||
statusUrl: 'https://chat.int.bayer.com',
|
||||
apiUrl: 'https://chat.int.bayer.com/api/v2/models?include_hidden_models=false&include_aliases=true',
|
||||
headers: {
|
||||
Authorization: 'Bearer $BAYER_MGA_API_KEY',
|
||||
},
|
||||
testModel: 'gpt-4o',
|
||||
},
|
||||
Cohere: {
|
||||
statusUrl: 'https://status.cohere.com/',
|
||||
apiUrl: 'https://api.cohere.ai/v1/models',
|
||||
@ -170,11 +180,20 @@ const PROVIDER_STATUS_URLS: Record<ProviderName, ProviderConfig> = {
|
||||
},
|
||||
testModel: 'deepseek-chat',
|
||||
},
|
||||
Hyperbolic: {
|
||||
statusUrl: 'https://status.hyperbolic.ai/',
|
||||
apiUrl: 'https://api.hyperbolic.ai/v1/models',
|
||||
headers: {
|
||||
Authorization: 'Bearer $HYPERBOLIC_API_KEY',
|
||||
},
|
||||
testModel: 'claude-3-opus-20240229',
|
||||
},
|
||||
};
|
||||
|
||||
const PROVIDER_ICONS: Record<ProviderName, IconType> = {
|
||||
AmazonBedrock: SiAmazon,
|
||||
Anthropic: FaBrain,
|
||||
BayerMGA: BsRobot,
|
||||
Cohere: BiChip,
|
||||
Google: SiGoogle,
|
||||
Groq: BsCloud,
|
||||
@ -186,6 +205,7 @@ const PROVIDER_ICONS: Record<ProviderName, IconType> = {
|
||||
Together: BsCloud,
|
||||
XAI: BsRobot,
|
||||
Deepseek: BiCodeBlock,
|
||||
Hyperbolic: BsCloud,
|
||||
};
|
||||
|
||||
const ServiceStatusTab = () => {
|
||||
@ -209,6 +229,7 @@ const ServiceStatusTab = () => {
|
||||
const envKeyMap: Record<ProviderName, string> = {
|
||||
OpenAI: 'OPENAI_API_KEY',
|
||||
Anthropic: 'ANTHROPIC_API_KEY',
|
||||
BayerMGA: 'BAYER_MGA_API_KEY',
|
||||
Cohere: 'COHERE_API_KEY',
|
||||
Google: 'GOOGLE_GENERATIVE_AI_API_KEY',
|
||||
HuggingFace: 'HuggingFace_API_KEY',
|
||||
@ -220,6 +241,7 @@ const ServiceStatusTab = () => {
|
||||
OpenRouter: 'OPEN_ROUTER_API_KEY',
|
||||
XAI: 'XAI_API_KEY',
|
||||
Deepseek: 'DEEPSEEK_API_KEY',
|
||||
Hyperbolic: 'HYPERBOLIC_API_KEY',
|
||||
};
|
||||
|
||||
const envKey = envKeyMap[provider];
|
||||
|
140
app/lib/modules/llm/providers/bayer-mga.ts
Normal file
140
app/lib/modules/llm/providers/bayer-mga.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import { BaseProvider } from '~/lib/modules/llm/base-provider';
|
||||
import type { ModelInfo } from '~/lib/modules/llm/types';
|
||||
import type { IProviderSetting } from '~/types/model';
|
||||
import type { LanguageModelV1 } from 'ai';
|
||||
import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { createScopedLogger } from '~/utils/logger';
|
||||
|
||||
const logger = createScopedLogger('BayerMGAProvider');
|
||||
|
||||
export default class BayerMGAProvider extends BaseProvider {
|
||||
name = 'BayerMGA';
|
||||
getApiKeyLink = 'https://chat.int.bayer.com';
|
||||
labelForGetApiKey = 'Get Bayer MGA API Key';
|
||||
|
||||
config = {
|
||||
baseUrl: 'https://chat.int.bayer.com/api/v2',
|
||||
apiTokenKey: 'BAYER_MGA_API_KEY',
|
||||
};
|
||||
|
||||
staticModels: ModelInfo[] = [
|
||||
// Temporary static models for testing inference flow
|
||||
{ name: 'claude-3-7-sonnet', label: 'Claude 3.7 Sonnet', provider: 'BayerMGA', maxTokenAllowed: 128000 },
|
||||
{ name: 'gpt-4o-mini', label: 'GPT-4o Mini', provider: 'BayerMGA', maxTokenAllowed: 128000 },
|
||||
// Add other common models if they appear in the UI for testing purposes
|
||||
];
|
||||
|
||||
async getDynamicModels(
|
||||
apiKeys?: Record<string, string>,
|
||||
settings?: IProviderSetting,
|
||||
serverEnv: Record<string, string> = {},
|
||||
): Promise<ModelInfo[]> {
|
||||
try {
|
||||
const { baseUrl, apiKey } = this.getProviderBaseUrlAndKey({
|
||||
apiKeys,
|
||||
providerSettings: settings,
|
||||
serverEnv,
|
||||
defaultBaseUrlKey: 'BAYER_MGA_API_BASE_URL',
|
||||
defaultApiTokenKey: 'BAYER_MGA_API_KEY',
|
||||
});
|
||||
|
||||
if (!baseUrl || !apiKey) {
|
||||
logger.warn('Missing baseUrl or apiKey configuration for Bayer MGA provider');
|
||||
return [];
|
||||
}
|
||||
|
||||
// Normalize base URL (remove trailing slash)
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
||||
|
||||
// Construct models URL with query parameters
|
||||
const modelsUrl = `${normalizedBaseUrl}/models?include_hidden_models=false&include_aliases=true`;
|
||||
logger.info(`Fetching models from ${modelsUrl}`);
|
||||
|
||||
// Make API request with proper headers
|
||||
const response = await fetch(modelsUrl, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Handle HTTP errors
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
logger.error(`Failed to fetch Bayer MGA models: ${response.status} ${response.statusText}`);
|
||||
logger.error(`Error details: ${errorText}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// Parse response
|
||||
const responseText = await response.text();
|
||||
let res;
|
||||
try {
|
||||
res = JSON.parse(responseText);
|
||||
} catch (e) {
|
||||
logger.error(`Invalid JSON response from Bayer MGA API: ${responseText.substring(0, 200)}...`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// Validate response structure
|
||||
if (!res.data || !Array.isArray(res.data)) {
|
||||
logger.error(`Invalid response format from Bayer MGA API: missing data array`);
|
||||
logger.debug(`Response: ${JSON.stringify(res).substring(0, 500)}...`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter for available models and map to ModelInfo format
|
||||
const models = res.data
|
||||
.filter((model: any) => model.model_status === 'available')
|
||||
.map((model: any) => ({
|
||||
name: model.model,
|
||||
label: model.name || model.model,
|
||||
provider: this.name,
|
||||
maxTokenAllowed: model.context_window || 8000,
|
||||
}));
|
||||
|
||||
logger.info(`Found ${models.length} available models from Bayer MGA`);
|
||||
return models;
|
||||
} catch (error) {
|
||||
logger.error(`Error fetching Bayer MGA models: ${error instanceof Error ? error.message : String(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
getModelInstance(options: {
|
||||
model: string;
|
||||
serverEnv: Env;
|
||||
apiKeys?: Record<string, string>;
|
||||
providerSettings?: Record<string, IProviderSetting>;
|
||||
}): LanguageModelV1 {
|
||||
const { model, serverEnv, apiKeys, providerSettings } = options;
|
||||
|
||||
const { baseUrl, apiKey } = this.getProviderBaseUrlAndKey({
|
||||
apiKeys,
|
||||
providerSettings: providerSettings?.[this.name],
|
||||
serverEnv: serverEnv as any,
|
||||
defaultBaseUrlKey: 'BAYER_MGA_API_BASE_URL',
|
||||
defaultApiTokenKey: 'BAYER_MGA_API_KEY',
|
||||
});
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error(`Missing API key for ${this.name} provider`);
|
||||
}
|
||||
|
||||
if (!baseUrl) {
|
||||
throw new Error(`Missing base URL for ${this.name} provider`);
|
||||
}
|
||||
|
||||
// Normalize base URL (remove trailing slash)
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
||||
|
||||
logger.info(`Creating model instance for ${model} using Bayer MGA API at ${normalizedBaseUrl}`);
|
||||
|
||||
const openai = createOpenAI({
|
||||
baseURL: normalizedBaseUrl,
|
||||
apiKey,
|
||||
});
|
||||
|
||||
return openai(model);
|
||||
}
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
import AmazonBedrockProvider from './providers/amazon-bedrock';
|
||||
import AnthropicProvider from './providers/anthropic';
|
||||
import BayerMGAProvider from './providers/bayer-mga';
|
||||
import CohereProvider from './providers/cohere';
|
||||
import DeepseekProvider from './providers/deepseek';
|
||||
import GithubProvider from './providers/github';
|
||||
import GoogleProvider from './providers/google';
|
||||
import GroqProvider from './providers/groq';
|
||||
import HuggingFaceProvider from './providers/huggingface';
|
||||
import HyperbolicProvider from './providers/hyperbolic';
|
||||
import LMStudioProvider from './providers/lmstudio';
|
||||
import MistralProvider from './providers/mistral';
|
||||
import OllamaProvider from './providers/ollama';
|
||||
@ -13,27 +17,25 @@ import OpenAIProvider from './providers/openai';
|
||||
import PerplexityProvider from './providers/perplexity';
|
||||
import TogetherProvider from './providers/together';
|
||||
import XAIProvider from './providers/xai';
|
||||
import HyperbolicProvider from './providers/hyperbolic';
|
||||
import AmazonBedrockProvider from './providers/amazon-bedrock';
|
||||
import GithubProvider from './providers/github';
|
||||
|
||||
export {
|
||||
AmazonBedrockProvider,
|
||||
AnthropicProvider,
|
||||
BayerMGAProvider,
|
||||
CohereProvider,
|
||||
DeepseekProvider,
|
||||
GithubProvider,
|
||||
GoogleProvider,
|
||||
GroqProvider,
|
||||
HuggingFaceProvider,
|
||||
HyperbolicProvider,
|
||||
LMStudioProvider,
|
||||
MistralProvider,
|
||||
OllamaProvider,
|
||||
OpenAIProvider,
|
||||
OpenRouterProvider,
|
||||
OpenAILikeProvider,
|
||||
PerplexityProvider,
|
||||
XAIProvider,
|
||||
TogetherProvider,
|
||||
LMStudioProvider,
|
||||
AmazonBedrockProvider,
|
||||
GithubProvider,
|
||||
XAIProvider,
|
||||
};
|
||||
|
286
app/routes/api.debug-bayer-mga.ts
Normal file
286
app/routes/api.debug-bayer-mga.ts
Normal file
@ -0,0 +1,286 @@
|
||||
import { type ActionFunctionArgs, type LoaderFunctionArgs, json } from '@remix-run/cloudflare';
|
||||
import { getApiKeysFromCookie, getProviderSettingsFromCookie } from '~/lib/api/cookies';
|
||||
import { createScopedLogger } from '~/utils/logger';
|
||||
import { BaseProvider, getOpenAILikeModel } from '~/lib/modules/llm/base-provider';
|
||||
import { generateText } from 'ai';
|
||||
|
||||
const logger = createScopedLogger('BayerMGADebug');
|
||||
|
||||
// Add CORS headers to all responses
|
||||
function addCorsHeaders(response: Response): Response {
|
||||
response.headers.set('Access-Control-Allow-Origin', '*');
|
||||
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
||||
return response;
|
||||
}
|
||||
|
||||
// Handle OPTIONS requests for CORS preflight
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
if (request.method === 'OPTIONS') {
|
||||
return addCorsHeaders(new Response(null, { status: 204 }));
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
const apiKey = url.searchParams.get('apiKey');
|
||||
const baseUrl = url.searchParams.get('baseUrl') || 'https://chat.int.bayer.com/api/v2';
|
||||
const model = url.searchParams.get('model') || 'gpt-4o-mini';
|
||||
|
||||
// Get API key from cookies if not provided in query params
|
||||
let effectiveApiKey = apiKey;
|
||||
if (!effectiveApiKey) {
|
||||
const cookieHeader = request.headers.get('Cookie');
|
||||
const apiKeys = getApiKeysFromCookie(cookieHeader);
|
||||
effectiveApiKey = apiKeys?.['BayerMGA'];
|
||||
}
|
||||
|
||||
if (!effectiveApiKey) {
|
||||
return addCorsHeaders(
|
||||
json(
|
||||
{
|
||||
success: false,
|
||||
error: 'No API key provided. Add ?apiKey=your_key to the URL or set it in the app settings.',
|
||||
tests: [],
|
||||
},
|
||||
{ status: 400 },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Normalize base URL (remove trailing slash)
|
||||
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
||||
|
||||
// Results container
|
||||
const results = {
|
||||
success: true,
|
||||
baseUrl: normalizedBaseUrl,
|
||||
model,
|
||||
apiKeyProvided: !!effectiveApiKey,
|
||||
apiKeyPrefix: effectiveApiKey ? `${effectiveApiKey.substring(0, 4)}...` : null,
|
||||
tests: [] as any[],
|
||||
};
|
||||
|
||||
// Test 1: Fetch models
|
||||
try {
|
||||
logger.info(`Testing models endpoint: ${normalizedBaseUrl}/models`);
|
||||
const modelsUrl = `${normalizedBaseUrl}/models?include_hidden_models=false&include_aliases=true`;
|
||||
|
||||
const modelsStartTime = Date.now();
|
||||
const modelsResponse = await fetch(modelsUrl, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${effectiveApiKey}`,
|
||||
},
|
||||
});
|
||||
const modelsEndTime = Date.now();
|
||||
|
||||
const modelsResponseText = await modelsResponse.text();
|
||||
let modelsData;
|
||||
let parsedModels = [];
|
||||
|
||||
try {
|
||||
modelsData = JSON.parse(modelsResponseText);
|
||||
if (modelsData.data && Array.isArray(modelsData.data)) {
|
||||
parsedModels = modelsData.data
|
||||
.filter((model: any) => model.model_status === 'available')
|
||||
.map((model: any) => ({
|
||||
model: model.model,
|
||||
name: model.name,
|
||||
context_window: model.context_window,
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
// JSON parse error
|
||||
}
|
||||
|
||||
results.tests.push({
|
||||
name: 'Models Endpoint',
|
||||
url: modelsUrl,
|
||||
success: modelsResponse.ok,
|
||||
status: modelsResponse.status,
|
||||
statusText: modelsResponse.statusText,
|
||||
duration: `${modelsEndTime - modelsStartTime}ms`,
|
||||
headers: Object.fromEntries(modelsResponse.headers.entries()),
|
||||
responsePreview: modelsResponseText.substring(0, 500) + (modelsResponseText.length > 500 ? '...' : ''),
|
||||
parsedModelsCount: parsedModels.length,
|
||||
availableModels: parsedModels.slice(0, 5), // First 5 models only
|
||||
});
|
||||
|
||||
// If models test failed, don't attempt completions test
|
||||
if (!modelsResponse.ok) {
|
||||
results.success = false;
|
||||
return addCorsHeaders(json(results));
|
||||
}
|
||||
|
||||
// Test 2: Chat completions
|
||||
logger.info(`Testing chat completions endpoint: ${normalizedBaseUrl}/chat/completions`);
|
||||
const completionsUrl = `${normalizedBaseUrl}/chat/completions`;
|
||||
|
||||
const completionsStartTime = Date.now();
|
||||
const completionsResponse = await fetch(completionsUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${effectiveApiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: model,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello from Buildify debug test. Please respond with a very short greeting.',
|
||||
},
|
||||
],
|
||||
temperature: 0.2,
|
||||
stream: false,
|
||||
}),
|
||||
});
|
||||
const completionsEndTime = Date.now();
|
||||
|
||||
const completionsResponseText = await completionsResponse.text();
|
||||
let completionsData;
|
||||
let completionContent = null;
|
||||
|
||||
try {
|
||||
completionsData = JSON.parse(completionsResponseText);
|
||||
if (completionsData.choices && completionsData.choices.length > 0) {
|
||||
completionContent = completionsData.choices[0].message?.content;
|
||||
}
|
||||
} catch (e) {
|
||||
// JSON parse error
|
||||
}
|
||||
|
||||
results.tests.push({
|
||||
name: 'Chat Completions Endpoint',
|
||||
url: completionsUrl,
|
||||
success: completionsResponse.ok,
|
||||
status: completionsResponse.status,
|
||||
statusText: completionsResponse.statusText,
|
||||
duration: `${completionsEndTime - completionsStartTime}ms`,
|
||||
headers: Object.fromEntries(completionsResponse.headers.entries()),
|
||||
responsePreview: completionsResponseText.substring(0, 500) + (completionsResponseText.length > 500 ? '...' : ''),
|
||||
completionContent,
|
||||
});
|
||||
|
||||
// Test 3: Using the AI SDK (same as the app)
|
||||
try {
|
||||
logger.info(`Testing AI SDK integration with ${normalizedBaseUrl}`);
|
||||
const sdkStartTime = Date.now();
|
||||
|
||||
// This mimics exactly how the app uses the provider
|
||||
const openaiLike = getOpenAILikeModel(normalizedBaseUrl, effectiveApiKey, model);
|
||||
|
||||
const result = await generateText({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello from Buildify AI SDK test. Please respond with a very short greeting.',
|
||||
},
|
||||
],
|
||||
model: openaiLike,
|
||||
maxTokens: 100,
|
||||
});
|
||||
|
||||
const sdkEndTime = Date.now();
|
||||
|
||||
results.tests.push({
|
||||
name: 'AI SDK Integration',
|
||||
success: true,
|
||||
duration: `${sdkEndTime - sdkStartTime}ms`,
|
||||
result: result,
|
||||
});
|
||||
} catch (error) {
|
||||
results.success = false;
|
||||
results.tests.push({
|
||||
name: 'AI SDK Integration',
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return addCorsHeaders(json(results));
|
||||
} catch (error) {
|
||||
results.success = false;
|
||||
results.error = error instanceof Error ? error.message : String(error);
|
||||
results.errorStack = error instanceof Error ? error.stack : undefined;
|
||||
|
||||
return addCorsHeaders(json(results, { status: 500 }));
|
||||
}
|
||||
}
|
||||
|
||||
// Handle POST requests for more complex testing
|
||||
export async function action({ request, context }: ActionFunctionArgs) {
|
||||
if (request.method === 'OPTIONS') {
|
||||
return addCorsHeaders(new Response(null, { status: 204 }));
|
||||
}
|
||||
|
||||
try {
|
||||
const { apiKey, baseUrl, model, messages, system } = await request.json();
|
||||
|
||||
// Get API key from cookies if not provided in request body
|
||||
let effectiveApiKey = apiKey;
|
||||
if (!effectiveApiKey) {
|
||||
const cookieHeader = request.headers.get('Cookie');
|
||||
const apiKeys = getApiKeysFromCookie(cookieHeader);
|
||||
effectiveApiKey = apiKeys?.['BayerMGA'];
|
||||
}
|
||||
|
||||
if (!effectiveApiKey) {
|
||||
return addCorsHeaders(
|
||||
json(
|
||||
{
|
||||
success: false,
|
||||
error: 'No API key provided in request body or cookies',
|
||||
},
|
||||
{ status: 400 },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Normalize base URL
|
||||
const normalizedBaseUrl = (baseUrl || 'https://chat.int.bayer.com/api/v2').endsWith('/')
|
||||
? (baseUrl || 'https://chat.int.bayer.com/api/v2').slice(0, -1)
|
||||
: (baseUrl || 'https://chat.int.bayer.com/api/v2');
|
||||
|
||||
const effectiveModel = model || 'gpt-4o-mini';
|
||||
|
||||
logger.info(`Testing AI SDK integration with custom messages: ${normalizedBaseUrl}`);
|
||||
|
||||
// Create OpenAI-like model instance (same as the provider)
|
||||
const openaiLike = getOpenAILikeModel(normalizedBaseUrl, effectiveApiKey, effectiveModel);
|
||||
|
||||
// Generate text using the AI SDK
|
||||
const result = await generateText({
|
||||
system: system || undefined,
|
||||
messages: messages || [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello from Buildify custom test. Please respond with a very short greeting.',
|
||||
},
|
||||
],
|
||||
model: openaiLike,
|
||||
maxTokens: 500,
|
||||
});
|
||||
|
||||
return addCorsHeaders(
|
||||
json({
|
||||
success: true,
|
||||
baseUrl: normalizedBaseUrl,
|
||||
model: effectiveModel,
|
||||
result,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(`Error in debug action: ${error instanceof Error ? error.message : String(error)}`);
|
||||
|
||||
return addCorsHeaders(
|
||||
json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
},
|
||||
{ status: 500 },
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
33319
package-lock.json
generated
Normal file
33319
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
143
test-bayer-mga.js
Normal file
143
test-bayer-mga.js
Normal file
@ -0,0 +1,143 @@
|
||||
// test-bayer-mga.js
|
||||
// A Node.js test script to debug the BayerMGA provider and identify the 500 error
|
||||
|
||||
// Import required modules
|
||||
const path = require('path');
|
||||
const { generateText } = require('ai');
|
||||
|
||||
// Set up paths for imports
|
||||
const APP_ROOT = path.resolve(__dirname);
|
||||
const PROVIDER_PATH = path.join(APP_ROOT, 'app/lib/modules/llm/providers/bayer-mga.js');
|
||||
|
||||
// Import the BayerMGA provider directly
|
||||
let BayerMGAProvider;
|
||||
try {
|
||||
// Try CommonJS import first
|
||||
BayerMGAProvider = require(PROVIDER_PATH).default;
|
||||
} catch (error) {
|
||||
console.error(`Error importing BayerMGA provider: ${error.message}`);
|
||||
console.error(`Make sure the path is correct: ${PROVIDER_PATH}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Test API key - replace with a real one for actual testing
|
||||
const TEST_API_KEY = process.env.BAYER_MGA_API_KEY || 'your-test-api-key';
|
||||
|
||||
// Mock parameters similar to what /api/llmcall would use
|
||||
const mockApiKeys = {
|
||||
BayerMGA: TEST_API_KEY
|
||||
};
|
||||
|
||||
const mockProviderSettings = {
|
||||
BayerMGA: {
|
||||
enabled: true,
|
||||
baseUrl: 'https://chat.int.bayer.com/api/v2'
|
||||
}
|
||||
};
|
||||
|
||||
const mockServerEnv = {
|
||||
BAYER_MGA_API_KEY: TEST_API_KEY,
|
||||
BAYER_MGA_API_BASE_URL: 'https://chat.int.bayer.com/api/v2'
|
||||
};
|
||||
|
||||
// Test model - use one that appears in the UI
|
||||
const TEST_MODEL = 'claude-3-7-sonnet';
|
||||
|
||||
async function testBayerMGAProvider() {
|
||||
console.log('='.repeat(80));
|
||||
console.log('BAYER MGA PROVIDER TEST');
|
||||
console.log('='.repeat(80));
|
||||
|
||||
try {
|
||||
console.log('Step 1: Creating BayerMGA provider instance...');
|
||||
const provider = new BayerMGAProvider();
|
||||
console.log('✅ Provider instance created successfully');
|
||||
console.log(`Provider name: ${provider.name}`);
|
||||
console.log(`Provider config:`, JSON.stringify(provider.config, null, 2));
|
||||
|
||||
console.log('\nStep 2: Testing getModelInstance method...');
|
||||
console.log('Parameters:');
|
||||
console.log(`- Model: ${TEST_MODEL}`);
|
||||
console.log(`- API Key: ${TEST_API_KEY.substring(0, 4)}...`);
|
||||
|
||||
// This is the exact flow used in /api/llmcall
|
||||
const modelInstance = provider.getModelInstance({
|
||||
model: TEST_MODEL,
|
||||
serverEnv: mockServerEnv,
|
||||
apiKeys: mockApiKeys,
|
||||
providerSettings: mockProviderSettings
|
||||
});
|
||||
|
||||
console.log('✅ getModelInstance succeeded');
|
||||
console.log(`Model instance type: ${typeof modelInstance}`);
|
||||
|
||||
console.log('\nStep 3: Testing generateText with the model instance...');
|
||||
// This mimics the generateText call in /api/llmcall
|
||||
const result = await generateText({
|
||||
system: 'You are a helpful assistant.',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: 'Hello, this is a test message from the BayerMGA test script.',
|
||||
},
|
||||
],
|
||||
model: modelInstance,
|
||||
maxTokens: 1000,
|
||||
});
|
||||
|
||||
console.log('✅ generateText succeeded');
|
||||
console.log('Response:');
|
||||
console.log(result.text);
|
||||
console.log('\nUsage:');
|
||||
console.log(JSON.stringify(result.usage, null, 2));
|
||||
|
||||
console.log('\n✅ All tests passed successfully!');
|
||||
} catch (error) {
|
||||
console.error('\n❌ Test failed with error:');
|
||||
console.error(`Error name: ${error.name}`);
|
||||
console.error(`Error message: ${error.message}`);
|
||||
|
||||
// Log additional error details if available
|
||||
if (error.cause) {
|
||||
console.error('\nError cause:');
|
||||
console.error(error.cause);
|
||||
}
|
||||
|
||||
if (error.stack) {
|
||||
console.error('\nStack trace:');
|
||||
console.error(error.stack);
|
||||
}
|
||||
|
||||
// Check for common error patterns
|
||||
if (error.message.includes('API key')) {
|
||||
console.error('\n🔑 This appears to be an API key issue. Make sure you have set a valid BAYER_MGA_API_KEY.');
|
||||
} else if (error.message.includes('network') || error.message.includes('ECONNREFUSED')) {
|
||||
console.error('\n🌐 This appears to be a network issue. Check your internet connection and the API base URL.');
|
||||
} else if (error.message.includes('not found') || error.message.includes('undefined')) {
|
||||
console.error('\n🔍 This appears to be a code issue. The provider or one of its methods might not be properly defined.');
|
||||
}
|
||||
|
||||
// Try to extract HTTP error details if present
|
||||
try {
|
||||
if (error.cause && error.cause.response) {
|
||||
console.error('\nHTTP Response Details:');
|
||||
console.error(`Status: ${error.cause.response.status}`);
|
||||
console.error(`Status Text: ${error.cause.response.statusText}`);
|
||||
|
||||
// Try to get response body
|
||||
if (typeof error.cause.response.text === 'function') {
|
||||
const responseText = await error.cause.response.text();
|
||||
console.error('Response Body:', responseText);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Could not extract HTTP response details:', e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test
|
||||
console.log('Starting BayerMGA provider test...');
|
||||
testBayerMGAProvider()
|
||||
.then(() => console.log('Test completed.'))
|
||||
.catch(err => console.error('Unhandled error in test:', err));
|
Loading…
Reference in New Issue
Block a user