UNPKG

@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

955 lines (954 loc) 84.8 kB
import { createVertex, } from "@ai-sdk/google-vertex"; import { createVertexAnthropic, } from "@ai-sdk/google-vertex/anthropic"; import { streamText, Output, } 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, DEFAULT_MAX_STEPS } from "../core/constants.js"; import { ModelConfigurationManager } from "../core/modelConfiguration.js"; import { validateApiKey, createVertexProjectConfig, createGoogleAuthConfig, } from "../utils/providerConfig.js"; import fs from "fs"; import path from "path"; import os from "os"; import dns from "dns"; import { buildMessagesArray } from "../utils/messageBuilder.js"; import { createProxyFetch } from "../proxy/proxyFetch.js"; // Enhanced Anthropic support with direct imports // Using the dual provider architecture from Vercel AI SDK const hasAnthropicSupport = () => { try { // Verify the anthropic module is available return typeof createVertexAnthropic === "function"; } catch { return false; } }; // Configuration helpers - now using consolidated utility const getVertexProjectId = () => { return validateApiKey(createVertexProjectConfig()); }; const getVertexLocation = () => { return (process.env.GOOGLE_CLOUD_LOCATION || process.env.VERTEX_LOCATION || process.env.GOOGLE_VERTEX_LOCATION || "us-central1"); }; const getDefaultVertexModel = () => { // Use gemini-2.5-flash as default - latest and best price-performance model // Override with VERTEX_MODEL environment variable if needed return process.env.VERTEX_MODEL || "gemini-2.5-flash"; }; const hasGoogleCredentials = () => { return !!(process.env.GOOGLE_APPLICATION_CREDENTIALS || process.env.GOOGLE_SERVICE_ACCOUNT_KEY || (process.env.GOOGLE_AUTH_CLIENT_EMAIL && process.env.GOOGLE_AUTH_PRIVATE_KEY)); }; // Enhanced Vertex settings creation with authentication fallback and proxy support const createVertexSettings = async () => { const baseSettings = { project: getVertexProjectId(), location: getVertexLocation(), fetch: createProxyFetch(), }; // 🎯 OPTION 2: Create credentials file from environment variables at runtime // This solves the problem where GOOGLE_APPLICATION_CREDENTIALS exists in ZSHRC locally // but the file doesn't exist on production servers // First, try to create credentials file from individual environment variables const requiredEnvVarsForFile = { type: process.env.GOOGLE_AUTH_TYPE, project_id: process.env.GOOGLE_AUTH_BREEZE_PROJECT_ID, private_key: process.env.GOOGLE_AUTH_PRIVATE_KEY, client_email: process.env.GOOGLE_AUTH_CLIENT_EMAIL, client_id: process.env.GOOGLE_AUTH_CLIENT_ID, auth_uri: process.env.GOOGLE_AUTH_AUTH_URI, token_uri: process.env.GOOGLE_AUTH_TOKEN_URI, auth_provider_x509_cert_url: process.env.GOOGLE_AUTH_AUTH_PROVIDER_CERT_URL, client_x509_cert_url: process.env.GOOGLE_AUTH_CLIENT_CERT_URL, universe_domain: process.env.GOOGLE_AUTH_UNIVERSE_DOMAIN, }; // If we have the essential fields, create a runtime credentials file if (requiredEnvVarsForFile.client_email && requiredEnvVarsForFile.private_key) { try { // Build complete service account credentials object const serviceAccountCredentials = { type: requiredEnvVarsForFile.type || "service_account", project_id: requiredEnvVarsForFile.project_id || getVertexProjectId(), private_key: requiredEnvVarsForFile.private_key.replace(/\\n/g, "\n"), client_email: requiredEnvVarsForFile.client_email, client_id: requiredEnvVarsForFile.client_id || "", auth_uri: requiredEnvVarsForFile.auth_uri || "https://accounts.google.com/o/oauth2/auth", token_uri: requiredEnvVarsForFile.token_uri || "https://oauth2.googleapis.com/token", auth_provider_x509_cert_url: requiredEnvVarsForFile.auth_provider_x509_cert_url || "https://www.googleapis.com/oauth2/v1/certs", client_x509_cert_url: requiredEnvVarsForFile.client_x509_cert_url || "", universe_domain: requiredEnvVarsForFile.universe_domain || "googleapis.com", }; // Create temporary credentials file const tmpDir = os.tmpdir(); const credentialsFileName = `google-credentials-${Date.now()}-${Math.random().toString(36).substring(2, 11)}.json`; const credentialsFilePath = path.join(tmpDir, credentialsFileName); fs.writeFileSync(credentialsFilePath, JSON.stringify(serviceAccountCredentials, null, 2)); // Set the environment variable to point to our runtime-created file process.env.GOOGLE_APPLICATION_CREDENTIALS = credentialsFilePath; // Now continue with the normal flow - check if the file exists const fileExists = fs.existsSync(credentialsFilePath); if (fileExists) { return baseSettings; } } catch { // Silent error handling for runtime credentials file creation } } // 🎯 OPTION 1: Check for principal account authentication (Accept any valid GOOGLE_APPLICATION_CREDENTIALS file (service account OR ADC)) if (process.env.GOOGLE_APPLICATION_CREDENTIALS) { const credentialsPath = process.env.GOOGLE_APPLICATION_CREDENTIALS; // Check if the credentials file exists let fileExists = false; try { fileExists = fs.existsSync(credentialsPath); } catch { fileExists = false; } if (fileExists) { return baseSettings; } } // Fallback to explicit credentials for development and production // Enhanced to check ALL required fields from the .env file configuration const requiredEnvVars = { type: process.env.GOOGLE_AUTH_TYPE, project_id: process.env.GOOGLE_AUTH_BREEZE_PROJECT_ID, private_key: process.env.GOOGLE_AUTH_PRIVATE_KEY, client_email: process.env.GOOGLE_AUTH_CLIENT_EMAIL, client_id: process.env.GOOGLE_AUTH_CLIENT_ID, auth_uri: process.env.GOOGLE_AUTH_AUTH_URI, token_uri: process.env.GOOGLE_AUTH_TOKEN_URI, auth_provider_x509_cert_url: process.env.GOOGLE_AUTH_AUTH_PROVIDER_CERT_URL, client_x509_cert_url: process.env.GOOGLE_AUTH_CLIENT_CERT_URL, universe_domain: process.env.GOOGLE_AUTH_UNIVERSE_DOMAIN, }; // Check if we have the minimal required fields (client_email and private_key are essential) if (requiredEnvVars.client_email && requiredEnvVars.private_key) { logger.debug("Using explicit service account credentials authentication", { authMethod: "explicit_service_account_credentials", hasType: !!requiredEnvVars.type, hasProjectId: !!requiredEnvVars.project_id, hasClientEmail: !!requiredEnvVars.client_email, hasPrivateKey: !!requiredEnvVars.private_key, hasClientId: !!requiredEnvVars.client_id, hasAuthUri: !!requiredEnvVars.auth_uri, hasTokenUri: !!requiredEnvVars.token_uri, hasAuthProviderCertUrl: !!requiredEnvVars.auth_provider_x509_cert_url, hasClientCertUrl: !!requiredEnvVars.client_x509_cert_url, hasUniverseDomain: !!requiredEnvVars.universe_domain, credentialsCompleteness: "using_individual_env_vars_as_fallback", }); // Build complete service account credentials object const serviceAccountCredentials = { type: requiredEnvVars.type || "service_account", project_id: requiredEnvVars.project_id || getVertexProjectId(), private_key: requiredEnvVars.private_key.replace(/\\n/g, "\n"), client_email: requiredEnvVars.client_email, client_id: requiredEnvVars.client_id || "", auth_uri: requiredEnvVars.auth_uri || "https://accounts.google.com/o/oauth2/auth", token_uri: requiredEnvVars.token_uri || "https://oauth2.googleapis.com/token", auth_provider_x509_cert_url: requiredEnvVars.auth_provider_x509_cert_url || "https://www.googleapis.com/oauth2/v1/certs", client_x509_cert_url: requiredEnvVars.client_x509_cert_url || "", universe_domain: requiredEnvVars.universe_domain || "googleapis.com", }; return { ...baseSettings, googleAuthOptions: { credentials: serviceAccountCredentials, }, }; } // Log comprehensive warning if no valid authentication is available logger.warn("No valid authentication found for Google Vertex AI", { authMethod: "none", authenticationAttempts: { principalAccountFile: { envVarSet: !!process.env.GOOGLE_APPLICATION_CREDENTIALS, filePath: process.env.GOOGLE_APPLICATION_CREDENTIALS || "NOT_SET", fileExists: false, // We already checked above }, explicitCredentials: { hasClientEmail: !!requiredEnvVars.client_email, hasPrivateKey: !!requiredEnvVars.private_key, hasProjectId: !!requiredEnvVars.project_id, hasType: !!requiredEnvVars.type, missingFields: Object.entries(requiredEnvVars) .filter(([_key, value]) => !value) .map(([key]) => key), }, }, troubleshooting: [ "1. Ensure GOOGLE_APPLICATION_CREDENTIALS points to an existing file, OR", "2. Set individual environment variables: GOOGLE_AUTH_CLIENT_EMAIL and GOOGLE_AUTH_PRIVATE_KEY", ], }); return baseSettings; }; // Create Anthropic-specific Vertex settings with the same authentication and proxy support const createVertexAnthropicSettings = async () => { const baseVertexSettings = await createVertexSettings(); // GoogleVertexAnthropicProviderSettings extends GoogleVertexProviderSettings // so we can use the same settings with proper typing return { project: baseVertexSettings.project, location: baseVertexSettings.location, fetch: baseVertexSettings.fetch, ...(baseVertexSettings.googleAuthOptions && { googleAuthOptions: baseVertexSettings.googleAuthOptions, }), }; }; // Helper function to determine if a model is an Anthropic model const isAnthropicModel = (modelName) => { return modelName.toLowerCase().includes("claude"); }; /** * Google Vertex AI Provider v2 - BaseProvider Implementation * * Features: * - Extends BaseProvider for shared functionality * - Preserves existing Google Cloud authentication * - Maintains Anthropic model support via dynamic imports * - Fresh model creation for each request * - Enhanced error handling with setup guidance * - Tool registration and context management */ export class GoogleVertexProvider extends BaseProvider { projectId; location; registeredTools = new Map(); toolContext = {}; // Memory-managed cache for model configuration lookups to avoid repeated calls // Uses WeakMap for automatic cleanup and bounded LRU for recently used models static modelConfigCache = new Map(); static modelConfigCacheTime = 0; static CACHE_DURATION = 5 * 60 * 1000; // 5 minutes static MAX_CACHE_SIZE = 50; // Prevent memory leaks by limiting cache size // Memory-managed cache for maxTokens handling decisions to optimize streaming performance static maxTokensCache = new Map(); static maxTokensCacheTime = 0; constructor(modelName, _providerName, sdk) { super(modelName, "vertex", sdk); // Validate Google Cloud credentials - now using consolidated utility if (!hasGoogleCredentials()) { validateApiKey(createGoogleAuthConfig()); } // Initialize Google Cloud configuration this.projectId = getVertexProjectId(); this.location = getVertexLocation(); logger.debug("Google Vertex AI BaseProvider v2 initialized", { modelName: this.modelName, projectId: this.projectId, location: this.location, provider: this.providerName, }); } getProviderName() { return "vertex"; } getDefaultModel() { return getDefaultVertexModel(); } /** * Returns the Vercel AI SDK model instance for Google Vertex * Creates fresh model instances for each request */ async getAISDKModel() { const model = await this.getModel(); return model; } /** * Initialize model creation logging and tracking */ initializeModelCreationLogging() { const modelCreationId = `vertex-model-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; const modelCreationStartTime = Date.now(); const modelCreationHrTimeStart = process.hrtime.bigint(); const modelName = this.modelName || getDefaultVertexModel(); logger.debug(`[GoogleVertexProvider] 🏭 LOG_POINT_V001_MODEL_CREATION_START`, { logPoint: "V001_MODEL_CREATION_START", modelCreationId, timestamp: new Date().toISOString(), modelCreationStartTime, modelCreationHrTimeStart: modelCreationHrTimeStart.toString(), requestedModel: this.modelName, resolvedModel: modelName, defaultModel: getDefaultVertexModel(), projectId: this.projectId, location: this.location, // Environment analysis for network issues environmentAnalysis: { httpProxy: process.env.HTTP_PROXY || process.env.http_proxy || "NOT_SET", httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy || "NOT_SET", googleAppCreds: process.env.GOOGLE_APPLICATION_CREDENTIALS || "NOT_SET", googleServiceKey: process.env.GOOGLE_SERVICE_ACCOUNT_KEY ? "SET" : "NOT_SET", nodeVersion: process.version, platform: process.platform, arch: process.arch, }, // Memory and performance baseline memoryUsage: process.memoryUsage(), cpuUsage: process.cpuUsage(), message: "Starting model creation with comprehensive environment analysis", }); return { modelCreationId, modelCreationStartTime, modelCreationHrTimeStart, modelName, }; } /** * Check if model is Anthropic-based and attempt creation */ async attemptAnthropicModelCreation(modelName, modelCreationId, modelCreationStartTime, modelCreationHrTimeStart) { const anthropicCheckStartTime = process.hrtime.bigint(); const isAnthropic = isAnthropicModel(modelName); logger.debug(`[GoogleVertexProvider] 🤖 LOG_POINT_V002_ANTHROPIC_CHECK`, { logPoint: "V002_ANTHROPIC_CHECK", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), anthropicCheckStartTimeNs: anthropicCheckStartTime.toString(), modelName, isAnthropicModel: isAnthropic, modelNameLowerCase: modelName.toLowerCase(), containsClaude: modelName.toLowerCase().includes("claude"), anthropicModelPatterns: ["claude"], message: "Checking if model is Anthropic-based", }); if (!isAnthropic) { return null; } const anthropicModelStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 🧠 LOG_POINT_V003_ANTHROPIC_MODEL_START`, { logPoint: "V003_ANTHROPIC_MODEL_START", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), anthropicModelStartTimeNs: anthropicModelStartTime.toString(), modelName, hasAnthropicSupport: hasAnthropicSupport(), message: "Creating Anthropic model using vertexAnthropic provider", }); logger.debug("Creating Anthropic model using vertexAnthropic provider", { modelName, }); if (!hasAnthropicSupport()) { logger.warn(`[GoogleVertexProvider] Anthropic support not available, falling back to Google model`); return null; } try { const anthropicModel = await this.createAnthropicModel(modelName); if (anthropicModel) { const anthropicModelSuccessTime = process.hrtime.bigint(); const anthropicModelDurationNs = anthropicModelSuccessTime - anthropicModelStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_V004_ANTHROPIC_MODEL_SUCCESS`, { logPoint: "V004_ANTHROPIC_MODEL_SUCCESS", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), anthropicModelDurationNs: anthropicModelDurationNs.toString(), anthropicModelDurationMs: Number(anthropicModelDurationNs) / 1000000, modelName, hasAnthropicModel: !!anthropicModel, anthropicModelType: typeof anthropicModel, memoryUsageAfterAnthropicCreation: process.memoryUsage(), message: "Anthropic model created successfully via vertexAnthropic", }); return anthropicModel; } // Anthropic model creation returned null const anthropicModelNullTime = process.hrtime.bigint(); const anthropicModelDurationNs = anthropicModelNullTime - anthropicModelStartTime; logger.warn(`[GoogleVertexProvider] ⚠️ LOG_POINT_V005_ANTHROPIC_MODEL_NULL`, { logPoint: "V005_ANTHROPIC_MODEL_NULL", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), anthropicModelDurationNs: anthropicModelDurationNs.toString(), anthropicModelDurationMs: Number(anthropicModelDurationNs) / 1000000, modelName, hasAnthropicModel: false, fallbackToGoogle: true, message: "Anthropic model creation returned null - falling back to Google model", }); } catch (error) { const anthropicModelErrorTime = process.hrtime.bigint(); const anthropicModelDurationNs = anthropicModelErrorTime - anthropicModelStartTime; logger.error(`[GoogleVertexProvider] ❌ LOG_POINT_V006_ANTHROPIC_MODEL_ERROR`, { logPoint: "V006_ANTHROPIC_MODEL_ERROR", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), anthropicModelDurationNs: anthropicModelDurationNs.toString(), anthropicModelDurationMs: Number(anthropicModelDurationNs) / 1000000, modelName, error: error instanceof Error ? error.message : String(error), errorName: error instanceof Error ? error.name : "UnknownError", errorStack: error instanceof Error ? error.stack : undefined, fallbackToGoogle: true, message: "Anthropic model creation failed - falling back to Google model", }); } // Fall back to regular model if Anthropic not available logger.warn(`Anthropic model ${modelName} requested but not available, falling back to Google model`); return null; } /** * Create Google Vertex model with comprehensive logging and error handling */ async createGoogleVertexModel(modelName, modelCreationId, modelCreationStartTime, modelCreationHrTimeStart, isAnthropic) { const googleModelStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 🌐 LOG_POINT_V007_GOOGLE_MODEL_START`, { logPoint: "V007_GOOGLE_MODEL_START", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), googleModelStartTimeNs: googleModelStartTime.toString(), modelName, projectId: this.projectId, location: this.location, reason: isAnthropic ? "ANTHROPIC_FALLBACK" : "DIRECT_GOOGLE_MODEL", message: "Creating fresh Google Vertex model with current settings", }); logger.debug("Creating Google Vertex model", { modelName, project: this.projectId, location: this.location, }); const vertexSettingsStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] ⚙️ LOG_POINT_V008_VERTEX_SETTINGS_START`, { logPoint: "V008_VERTEX_SETTINGS_START", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), vertexSettingsStartTimeNs: vertexSettingsStartTime.toString(), // Network configuration analysis networkConfig: { projectId: this.projectId, location: this.location, expectedEndpoint: `https://${this.location}-aiplatform.googleapis.com`, httpProxy: process.env.HTTP_PROXY || process.env.http_proxy, httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy, noProxy: process.env.NO_PROXY || process.env.no_proxy, proxyConfigured: !!(process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy), }, message: "Starting Vertex settings creation with network configuration analysis", }); try { const vertexSettings = await createVertexSettings(); const vertexSettingsEndTime = process.hrtime.bigint(); const vertexSettingsDurationNs = vertexSettingsEndTime - vertexSettingsStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_V009_VERTEX_SETTINGS_SUCCESS`, { logPoint: "V009_VERTEX_SETTINGS_SUCCESS", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), vertexSettingsDurationNs: vertexSettingsDurationNs.toString(), vertexSettingsDurationMs: Number(vertexSettingsDurationNs) / 1000000, // Settings analysis vertexSettingsAnalysis: { hasSettings: !!vertexSettings, settingsType: typeof vertexSettings, settingsKeys: vertexSettings ? Object.keys(vertexSettings) : [], projectId: vertexSettings?.project, location: vertexSettings?.location, hasFetch: !!vertexSettings?.fetch, hasGoogleAuthOptions: !!vertexSettings?.googleAuthOptions, settingsSize: vertexSettings ? JSON.stringify(vertexSettings).length : 0, }, message: "Vertex settings created successfully", }); return await this.createVertexInstance(vertexSettings, modelName, modelCreationId, modelCreationStartTime, modelCreationHrTimeStart); } catch (error) { const vertexSettingsErrorTime = process.hrtime.bigint(); const vertexSettingsDurationNs = vertexSettingsErrorTime - vertexSettingsStartTime; const totalErrorDurationNs = vertexSettingsErrorTime - modelCreationHrTimeStart; logger.error(`[GoogleVertexProvider] ❌ LOG_POINT_V014_VERTEX_SETTINGS_ERROR`, { logPoint: "V014_VERTEX_SETTINGS_ERROR", modelCreationId, timestamp: new Date().toISOString(), totalElapsedMs: Date.now() - modelCreationStartTime, totalElapsedNs: totalErrorDurationNs.toString(), totalErrorDurationMs: Number(totalErrorDurationNs) / 1000000, vertexSettingsDurationNs: vertexSettingsDurationNs.toString(), vertexSettingsDurationMs: Number(vertexSettingsDurationNs) / 1000000, // Comprehensive error analysis error: error instanceof Error ? error.message : String(error), errorName: error instanceof Error ? error.name : "UnknownError", errorStack: error instanceof Error ? error.stack : undefined, // Network diagnostic information networkDiagnostics: { errorCode: error?.code || "UNKNOWN", errorErrno: error?.errno || "UNKNOWN", errorAddress: error?.address || "UNKNOWN", errorPort: error?.port || "UNKNOWN", errorSyscall: error?.syscall || "UNKNOWN", errorHostname: error?.hostname || "UNKNOWN", isTimeoutError: error instanceof Error && (error.message.includes("timeout") || error.message.includes("ETIMEDOUT")), isNetworkError: error instanceof Error && (error.message.includes("ENOTFOUND") || error.message.includes("ECONNREFUSED") || error.message.includes("ETIMEDOUT")), isAuthError: error instanceof Error && (error.message.includes("PERMISSION_DENIED") || error.message.includes("401") || error.message.includes("403")), infrastructureIssue: error instanceof Error && error.message.includes("ETIMEDOUT") && error.message.includes("aiplatform.googleapis.com"), }, // Environment at error time errorEnvironment: { httpProxy: process.env.HTTP_PROXY || process.env.http_proxy, httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy, googleAppCreds: process.env.GOOGLE_APPLICATION_CREDENTIALS, hasGoogleServiceKey: !!process.env.GOOGLE_SERVICE_ACCOUNT_KEY, nodeVersion: process.version, memoryUsage: process.memoryUsage(), uptime: process.uptime(), }, message: "Vertex settings creation failed - critical network/authentication error", }); throw error; } } /** * Create Vertex AI instance and model with comprehensive logging */ async createVertexInstance(vertexSettings, modelName, modelCreationId, modelCreationStartTime, modelCreationHrTimeStart) { const vertexInstanceStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 🏗️ LOG_POINT_V010_VERTEX_INSTANCE_START`, { logPoint: "V010_VERTEX_INSTANCE_START", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), vertexInstanceStartTimeNs: vertexInstanceStartTime.toString(), // Pre-creation network environment networkEnvironment: { dnsServers: (() => { try { return dns.getServers ? dns.getServers() : "NOT_AVAILABLE"; } catch { return "NOT_AVAILABLE"; } })(), networkInterfaces: (() => { try { return Object.keys(os.networkInterfaces()); } catch { return []; } })(), hostname: (() => { try { return os.hostname(); } catch { return "UNKNOWN"; } })(), platform: (() => { try { return os.platform(); } catch { return "UNKNOWN"; } })(), release: (() => { try { return os.release(); } catch { return "UNKNOWN"; } })(), }, message: "Creating Vertex AI instance", }); const vertex = createVertex(vertexSettings); const vertexInstanceEndTime = process.hrtime.bigint(); const vertexInstanceDurationNs = vertexInstanceEndTime - vertexInstanceStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_V011_VERTEX_INSTANCE_SUCCESS`, { logPoint: "V011_VERTEX_INSTANCE_SUCCESS", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), vertexInstanceDurationNs: vertexInstanceDurationNs.toString(), vertexInstanceDurationMs: Number(vertexInstanceDurationNs) / 1000000, hasVertexInstance: !!vertex, vertexInstanceType: typeof vertex, message: "Vertex AI instance created successfully", }); const modelInstanceStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 🎯 LOG_POINT_V012_MODEL_INSTANCE_START`, { logPoint: "V012_MODEL_INSTANCE_START", modelCreationId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - modelCreationStartTime, elapsedNs: (process.hrtime.bigint() - modelCreationHrTimeStart).toString(), modelInstanceStartTimeNs: modelInstanceStartTime.toString(), modelName, hasVertexInstance: !!vertex, message: "Creating model instance from Vertex AI instance", }); const model = vertex(modelName); const modelInstanceEndTime = process.hrtime.bigint(); const modelInstanceDurationNs = modelInstanceEndTime - modelInstanceStartTime; const totalModelCreationDurationNs = modelInstanceEndTime - modelCreationHrTimeStart; logger.info(`[GoogleVertexProvider] 🏁 LOG_POINT_V013_MODEL_CREATION_COMPLETE`, { logPoint: "V013_MODEL_CREATION_COMPLETE", modelCreationId, timestamp: new Date().toISOString(), totalElapsedMs: Date.now() - modelCreationStartTime, totalElapsedNs: totalModelCreationDurationNs.toString(), totalDurationMs: Number(totalModelCreationDurationNs) / 1000000, modelInstanceDurationNs: modelInstanceDurationNs.toString(), modelInstanceDurationMs: Number(modelInstanceDurationNs) / 1000000, // Final model analysis finalModel: { hasModel: !!model, modelType: typeof model, modelName, isAnthropicModel: isAnthropicModel(modelName), projectId: this.projectId, location: this.location, }, // Performance summary performanceSummary: { vertexSettingsDurationMs: Number(vertexInstanceDurationNs) / 1000000, vertexInstanceDurationMs: Number(vertexInstanceDurationNs) / 1000000, modelInstanceDurationMs: Number(modelInstanceDurationNs) / 1000000, totalDurationMs: Number(totalModelCreationDurationNs) / 1000000, }, // Memory usage finalMemoryUsage: process.memoryUsage(), message: "Model creation completed successfully - ready for API calls", }); return model; } /** * Gets the appropriate model instance (Google or Anthropic) * Uses dual provider architecture for proper model routing * Creates fresh instances for each request to ensure proper authentication */ async getModel() { // Initialize logging and setup const { modelCreationId, modelCreationStartTime, modelCreationHrTimeStart, modelName, } = this.initializeModelCreationLogging(); // Check if this is an Anthropic model and attempt creation const anthropicModel = await this.attemptAnthropicModelCreation(modelName, modelCreationId, modelCreationStartTime, modelCreationHrTimeStart); if (anthropicModel) { return anthropicModel; } // Fall back to Google Vertex model creation return await this.createGoogleVertexModel(modelName, modelCreationId, modelCreationStartTime, modelCreationHrTimeStart, isAnthropicModel(modelName)); } // executeGenerate removed - BaseProvider handles all generation with tools /** * Log stream execution start with comprehensive analysis */ logStreamExecutionStart(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, functionTag, options, analysisSchema) { logger.info(`[GoogleVertexProvider] 🎬 LOG_POINT_S001_STREAM_EXECUTION_START`, { logPoint: "S001_STREAM_EXECUTION_START", streamExecutionId, timestamp: new Date().toISOString(), streamExecutionStartTime, streamExecutionHrTimeStart: streamExecutionHrTimeStart.toString(), functionTag, // Input analysis inputAnalysis: { hasOptions: !!options, optionsType: typeof options, optionsKeys: options ? Object.keys(options) : [], hasInputText: !!options?.input?.text, inputTextLength: options?.input?.text?.length || 0, inputTextPreview: options?.input?.text?.substring(0, 200) || "NO_TEXT", hasAnalysisSchema: !!analysisSchema, schemaType: analysisSchema ? typeof analysisSchema : "NO_SCHEMA", disableTools: options?.disableTools || false, temperature: options?.temperature, maxTokens: options?.maxTokens, }, // Provider context providerContext: { modelName: this.modelName, providerName: this.providerName, projectId: this.projectId, location: this.location, defaultTimeout: this.defaultTimeout, }, // Network environment networkEnvironment: { httpProxy: process.env.HTTP_PROXY || process.env.http_proxy || "NOT_SET", httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy || "NOT_SET", googleAppCreds: process.env.GOOGLE_APPLICATION_CREDENTIALS || "NOT_SET", hasGoogleServiceKey: !!process.env.GOOGLE_SERVICE_ACCOUNT_KEY, expectedEndpoint: `https://${this.location}-aiplatform.googleapis.com`, proxyConfigured: !!(process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy), }, // Performance baseline memoryUsage: process.memoryUsage(), cpuUsage: process.cpuUsage(), message: "Stream execution starting with comprehensive analysis", }); } /** * Log timeout setup process */ logTimeoutSetup(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, timeoutSetupStartTime, timeout) { logger.debug(`[GoogleVertexProvider] ⏰ LOG_POINT_S002_TIMEOUT_SETUP`, { logPoint: "S002_TIMEOUT_SETUP", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), timeoutSetupStartTimeNs: timeoutSetupStartTime.toString(), timeout, providerName: this.providerName, streamType: "stream", message: "Setting up timeout controller for stream execution", }); } /** * Log successful timeout setup */ logTimeoutSetupSuccess(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, timeoutSetupStartTime, timeoutController, timeout) { const timeoutSetupEndTime = process.hrtime.bigint(); const timeoutSetupDurationNs = timeoutSetupEndTime - timeoutSetupStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_S003_TIMEOUT_SETUP_SUCCESS`, { logPoint: "S003_TIMEOUT_SETUP_SUCCESS", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), timeoutSetupDurationNs: timeoutSetupDurationNs.toString(), timeoutSetupDurationMs: Number(timeoutSetupDurationNs) / 1000000, hasTimeoutController: !!timeoutController, timeoutValue: timeout, message: "Timeout controller setup completed", }); } /** * Log and perform stream options validation */ logAndValidateStreamOptions(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, options) { const validationStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] ✔️ LOG_POINT_S004_VALIDATION_START`, { logPoint: "S004_VALIDATION_START", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), validationStartTimeNs: validationStartTime.toString(), message: "Starting stream options validation", }); this.validateStreamOptions(options); const validationEndTime = process.hrtime.bigint(); const validationDurationNs = validationEndTime - validationStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_S005_VALIDATION_SUCCESS`, { logPoint: "S005_VALIDATION_SUCCESS", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), validationDurationNs: validationDurationNs.toString(), validationDurationMs: Number(validationDurationNs) / 1000000, message: "Stream options validation successful", }); } /** * Log start of message building process */ logMessageBuildStart(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart) { const messagesBuildStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 📝 LOG_POINT_S006_MESSAGES_BUILD_START`, { logPoint: "S006_MESSAGES_BUILD_START", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), messagesBuildStartTimeNs: messagesBuildStartTime.toString(), message: "Starting message array building", }); return messagesBuildStartTime; } /** * Log successful message building */ logMessageBuildSuccess(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, messagesBuildStartTime, messages) { const messagesBuildEndTime = process.hrtime.bigint(); const messagesBuildDurationNs = messagesBuildEndTime - messagesBuildStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_S007_MESSAGES_BUILD_SUCCESS`, { logPoint: "S007_MESSAGES_BUILD_SUCCESS", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), messagesBuildDurationNs: messagesBuildDurationNs.toString(), messagesBuildDurationMs: Number(messagesBuildDurationNs) / 1000000, messagesCount: Array.isArray(messages) ? messages.length : 0, messagesType: typeof messages, hasMessages: !!messages, message: "Message array built successfully", }); } async executeStream(options, analysisSchema) { // Initialize stream execution tracking const streamExecutionId = `vertex-stream-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; const streamExecutionStartTime = Date.now(); const streamExecutionHrTimeStart = process.hrtime.bigint(); const functionTag = "GoogleVertexProvider.executeStream"; let chunkCount = 0; // Log stream execution start this.logStreamExecutionStart(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, functionTag, options, analysisSchema); // Setup timeout controller const timeoutSetupStartTime = process.hrtime.bigint(); const timeout = this.getTimeout(options); this.logTimeoutSetup(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, timeoutSetupStartTime, timeout); const timeoutController = createTimeoutController(timeout, this.providerName, "stream"); this.logTimeoutSetupSuccess(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, timeoutSetupStartTime, timeoutController, timeout); try { // Validate stream options with logging this.logAndValidateStreamOptions(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, options); // Build messages with logging const messagesBuildStartTime = this.logMessageBuildStart(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart); // Build message array from options const messages = buildMessagesArray(options); this.logMessageBuildSuccess(streamExecutionId, streamExecutionStartTime, streamExecutionHrTimeStart, messagesBuildStartTime, messages); // Log stream request details logger.debug(`[GoogleVertexProvider] 🚀 LOG_POINT_S008_STREAM_REQUEST_DETAILS`, { logPoint: "S008_STREAM_REQUEST_DETAILS", streamExecutionId, streamRequestDetails: { modelName: this.modelName, promptLength: options.input.text.length, hasSchema: !!analysisSchema, messagesCount: Array.isArray(messages) ? messages.length : 0, temperature: options?.temperature, maxTokens: options?.maxTokens, disableTools: options?.disableTools || false, }, message: "Starting comprehensive stream request processing", }); // 🚀 EXHAUSTIVE LOGGING POINT S009: MODEL CREATION FOR STREAM const modelCreationStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 🏭 LOG_POINT_S009_MODEL_CREATION_FOR_STREAM`, { logPoint: "S009_MODEL_CREATION_FOR_STREAM", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), modelCreationStartTimeNs: modelCreationStartTime.toString(), requestedModel: this.modelName, message: "Starting model creation for stream execution (this will include network setup)", }); const model = await this.getModel(); // This is where network connection happens! const modelCreationEndTime = process.hrtime.bigint(); const modelCreationDurationNs = modelCreationEndTime - modelCreationStartTime; logger.info(`[GoogleVertexProvider] ✅ LOG_POINT_S010_MODEL_CREATION_SUCCESS`, { logPoint: "S010_MODEL_CREATION_SUCCESS", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), modelCreationDurationNs: modelCreationDurationNs.toString(), modelCreationDurationMs: Number(modelCreationDurationNs) / 1000000, hasModel: !!model, modelType: typeof model, message: "Model creation completed successfully - network connection established", }); // 🚀 EXHAUSTIVE LOGGING POINT S011: TOOLS SETUP FOR STREAMING const toolsSetupStartTime = process.hrtime.bigint(); logger.debug(`[GoogleVertexProvider] 🛠️ LOG_POINT_S011_TOOLS_SETUP_START`, { logPoint: "S011_TOOLS_SETUP_START", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), toolsSetupStartTimeNs: toolsSetupStartTime.toString(), disableTools: options?.disableTools || false, supportsTools: this.supportsTools(), message: "Setting up tools for streaming", }); // Get all available tools (direct + MCP + external) for streaming const shouldUseTools = !options.disableTools && this.supportsTools(); const tools = shouldUseTools ? await this.getAllTools() : {}; const toolsSetupEndTime = process.hrtime.bigint(); const toolsSetupDurationNs = toolsSetupEndTime - toolsSetupStartTime; logger.debug(`[GoogleVertexProvider] ✅ LOG_POINT_S012_TOOLS_SETUP_SUCCESS`, { logPoint: "S012_TOOLS_SETUP_SUCCESS", streamExecutionId, timestamp: new Date().toISOString(), elapsedMs: Date.now() - streamExecutionStartTime, elapsedNs: (process.hrtime.bigint() - streamExecutionHrTimeStart).toString(), toolsSetupDurationNs: toolsSetupDurationNs.toString(), toolsSetupDurationMs: Number(toolsSetupDurationNs) / 1000000, shouldUseTools, toolCount: Object.keys(tools).length, toolNames: Object.keys(tools), hasTools: Object.keys(tools).length > 0, message: "Tools setup completed for streaming", }); logger.debug(`${functionTag}: Tools for streaming`, { shouldUseTools, toolCount: Object.keys(tools).length, toolNames: Object.keys(tools), }); // Model-specific maxTokens handling const modelName = this.modelName || getDefaultVertexModel(); // Use cached model configuration to determine maxTokens handling for streaming performance // This avoids hardcoded model-specific logic and repeated config lookups const shouldSetMaxTokens = this.shouldSetMaxTokensCached(modelName); const maxTokens = shouldSetMaxTokens ? options.maxTokens || DEFAULT_MAX_TOKENS : undefined; // Build complete stream options with proper typing let streamOptions = { model: model, messages: messages, temperature: options.temperature, ...(maxTokens && { maxTokens }), // Add tools support for streaming ...(shouldUseTools &&