mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
feat: Add comprehensive debugging tools for Bayer MGA integration
- Added debug guide with manual testing procedures - Created debug API route for testing endpoints - Includes models endpoint, chat completions, and AI SDK testing - Provides detailed error logging and response analysis - CORS support for browser testing
This commit is contained in:
parent
2c9926fc9d
commit
671fc51fa5
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 },
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user