import type { ZodType } from "zod"; import { AIProviderName } from "../constants/enums.js"; import { BaseProvider } from "../core/baseProvider.js"; import type { EnhancedGenerateResult, TextGenerationOptions, StreamOptions, StreamResult, VertexAnthropicMessage, ChatMessage, MinimalChatMessage } from "../types/index.js"; import type { Schema, LanguageModel } from "../types/index.js"; export declare function buildAnthropicHistoryMessages(conversationMessages: Array): VertexAnthropicMessage[]; export declare function appendUserMessage(messages: VertexAnthropicMessage[], content: VertexAnthropicMessage["content"]): void; /** * Recursively strip JSON-schema fields that Vertex Gemini's function-call AND * `responseSchema` (structured output) validators reject with 400 * INVALID_ARGUMENT. Vertex implements OpenAPI 3.0 Schema strictly and rejects * extension fields that the broader JSON Schema spec allows. The fields * stripped here have no semantic meaning for the model, so removing them is * safe for every caller. * * Fields removed: * - `additionalProperties` — extension; Vertex rejects on any nested object. * - `default` — Vertex rejects defaults on object/array-typed properties and * on properties that are also marked `required`. Safest to strip globally * because the model never inspects them. * - `$schema`, `$id`, `$ref`, `definitions`, `$defs` — JSON-Schema-meta * fields that Vertex doesn't recognise. * - `examples` — accepted by some Gemini variants but not 2.5-flash; strip * to avoid the model rejecting tool schemas under that path. * - `errorMessage` — emitted by `convertZodToJsonSchema` (which enables * zod-to-json-schema's `errorMessages: true`) for any field carrying a * custom message, e.g. `z.string().regex(re, { message })`. Vertex's * `response_schema` validator rejects it with `Unknown name "errorMessage" * … Cannot find field`, failing the whole structured-output request. * * Exported for deterministic unit testing of the sanitization contract. */ export declare function stripAdditionalPropertiesDeep(schema: Record | undefined): void; /** * Resolve the effective Vertex region for a given model. * * Policy (matches the bugfixes-suite contract): * - Every Gemini model (`gemini-*`) is force-routed to the `global` endpoint * regardless of any caller-supplied region. Regional endpoints 404 for * Gemini 3.x previews and the regional/global behaviour for 2.x is * consistent enough that pinning all Gemini traffic to global is the * right safe default. The legacy `GLOBAL_LOCATION_MODELS` allowlist is * kept as a defence-in-depth fallback so any non-`gemini-` identifiers * that still need global (e.g. image-gen aliases) keep working. * - Non-Gemini models (Claude on Vertex, embeddings, custom models) keep * the caller-supplied region or fall back to env-derived defaults. * * @param modelName - The target model identifier. * @param configuredLocation - Caller-provided region (e.g. options.region). * Used as the fallback for non-Gemini models; ignored for Gemini. * @returns The region string to pass to the @google/genai client. */ export declare const resolveVertexLocation: (modelName: string | undefined, configuredLocation?: string) => string; /** * 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 * * @important Tools + Schema Support (Fixed) * Gemini models on Vertex AI now support combining function calling (tools) with * structured output (JSON schema) simultaneously. The fix works by NOT setting * `responseMimeType: "application/json"` when tools are present, which was * causing the Google API error. * * The `responseSchema` is still set to guide the output structure, allowing * tools to execute AND the final output to follow the schema format. * * @example Gemini models with tools + schemas * ```typescript * const provider = new GoogleVertexProvider("gemini-2.5-flash"); * const result = await provider.generate({ * input: { text: "Analyze data using tools" }, * schema: MySchema, * output: { format: "json" }, * // No need for disableTools: true anymore! * }); * ``` * * @example Claude models (always supported both) * ```typescript * const provider = new GoogleVertexProvider("claude-3-5-sonnet-20241022"); * const result = await provider.generate({ * input: { text: "Analyze data" }, * schema: MySchema, * output: { format: "json" } * }); * ``` * * @note "Too many states for serving" errors can still occur with very complex schemas + tools. * Solution: Simplify schema or reduce number of tools if this occurs. * @see https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models */ export declare class GoogleVertexProvider extends BaseProvider { private projectId; private location; private registeredTools; private toolContext; private static modelConfigCache; private static modelConfigCacheTime; private static readonly CACHE_DURATION; private static readonly MAX_CACHE_SIZE; private static maxTokensCache; private static maxTokensCacheTime; constructor(modelName?: string, _providerName?: string, sdk?: unknown, region?: string, credentials?: Record); protected getProviderName(): AIProviderName; protected getDefaultModel(): string; /** * Returns the Vercel AI SDK model instance for Google Vertex * Creates fresh model instances for each request */ protected getAISDKModel(): Promise; /** * Initialize model creation tracking */ private initializeModelCreationLogging; /** * Check if model is Anthropic-based and attempt creation */ private attemptAnthropicModelCreation; /** * Create Google Vertex model with comprehensive logging and error handling */ private createGoogleVertexModel; /** * @deprecated This method is no longer used. All models now use native SDKs. */ private createVertexInstance; /** * 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 */ private getModel; /** * Validate stream options */ private validateStreamOptionsOnly; protected executeStream(options: StreamOptions, _analysisSchema?: ZodType | Schema): Promise; /** * Emit `stream:end` so the Pipeline B observability listener creates a * `model.generation` span for native Vertex stream traffic. Mirrors * `emitGenerationEnd` (used by `generate()`). */ private emitStreamEnd; /** * Create @google/genai client configured for Vertex AI */ private createVertexGenAIClient; /** * Execute stream using native @google/genai SDK for Gemini 3 models on Vertex AI * This bypasses @ai-sdk/google-vertex to properly handle thought_signature */ private executeNativeGemini3Stream; /** * Execute generate using native @google/genai SDK for Gemini 3 models on Vertex AI * This bypasses @ai-sdk/google-vertex to properly handle thought_signature */ private executeNativeGemini3Generate; /** * One-shot, tools-disabled model call used when a native Gemini agentic loop * is force-terminated by the step cap with no text produced. Lets the model * synthesize a final answer from the function results already in `contents` * instead of returning a canned placeholder (Bug 1, part b). * * Tools are disabled by OMITTING `config.tools` — the codebase's established * mechanism. `@google/genai`'s `FunctionCallingConfigMode.NONE` is documented * as equivalent to passing no function declarations, and `functionCallingConfig` * is not used anywhere in this codebase. When the structured-output * (`final_result`) pattern was active, a trailing instruction countermands the * earlier "you MUST call final_result" directive so the model answers in plain * text. Never throws — returns empty text so the caller falls back to the * graceful cap message (buildToolLoopCapMessage), guaranteeing no new failure * path. */ private synthesizeFinalAnswerWithoutTools; /** * Create native AnthropicVertex client for Claude models */ private createAnthropicVertexClient; /** * Execute stream using native @anthropic-ai/vertex-sdk for Claude models on Vertex AI * This bypasses @ai-sdk/google-vertex completely and uses Anthropic's native SDK */ private executeNativeAnthropicStream; /** * Execute generate using native @anthropic-ai/vertex-sdk for Claude models on Vertex AI */ private executeNativeAnthropicGenerate; /** * Process CSV files and append content to options.input.text * This ensures CSV data is available in the prompt for native Gemini 3 SDK calls * Returns a new options object with modified input (immutable pattern) */ private processCSVFilesForNativeSDK; /** * Override stream to handle image generation models * Image models don't support streaming, so we fall back to generate */ stream(optionsOrPrompt: StreamOptions | string): Promise; /** * Override generate to route ALL models to native SDKs * No more @ai-sdk/google-vertex dependency */ generate(optionsOrPrompt: TextGenerationOptions | string): Promise; /** * Invoke `options.onFinish` with the lifecycle payload shape consumers * (and `test:middleware`) expect. Pulled out so generate / image-gen / * Anthropic / Gemini code paths share one implementation. Errors thrown * by the user's callback are swallowed so they cannot poison the * primary generate path — same contract as the AI SDK middleware * wrapGenerate uses. */ private fireGenerateOnFinish; /** * Invoke `options.onError` with the lifecycle payload shape consumers * (and `test:middleware`) expect. Mirrors {@link fireGenerateOnFinish}. */ private fireGenerateOnError; /** * Wrap a {@link StreamResult} so each text chunk drives `options.onChunk` * and the final yield drives `options.onFinish`. Pipeline A providers get * this for free via the AI SDK `wrapStream` middleware; native @google/genai * bypasses that wrapper, so native consumers need their lifecycle * callbacks invoked from here. */ private wrapStreamResultWithLifecycle; /** * Re-apply getter-based accessor properties from a source StreamResult onto * a wrapper copy. Wrapper spreads (`{ ...result }`) invoke and SNAPSHOT * enumerable getters at wrap time — for background-loop streams (the native * Anthropic path) that resolve finishReason / structuredOutput / toolCalls * only as the consumer drains, the snapshot is permanently undefined/empty. * Copying the accessor descriptors keeps the wrapped result live. Results * built from plain data properties (the buffered Gemini paths) have no * getters and pass through untouched. */ private preserveStreamResultAccessors; /** * Attach `gen_ai.usage.*` and `neurolink.cost` attributes to a span. * Pulled out so the generate / stream / image-gen paths share one * implementation, and so observability/tracing tests find consistent * attributes regardless of which native sub-route fulfilled the request. */ private attachUsageAndCostAttributes; /** * Emit `generation:end` so the Pipeline B observability listener creates * the corresponding `model.generation` span. Vertex bypasses the AI SDK * (and therefore the experimental_telemetry plumbing), so this hand-off * is the only way native Vertex calls show up in Langfuse / Pipeline B * exporters. Mirrors the Bedrock + Ollama pattern. */ private emitGenerationEnd; /** * Emit a `turn:lifecycle` event on the SDK emitter (alongside * tool:start/tool:end) so loop conditions that previously only reached * process logs — step-cap, time-limit, stall, abort, tool timeouts, * malformed-call retries — are observable by consumers' own pipelines. */ private emitTurnEvent; /** * Pick the honest terminal message for a native-loop exit by its ACTUAL * cause. The step-cap text is the fallback for genuine budget exhaustion * only — time/stall/abort exits must never claim a step limit was reached * (the 2026-07-03 "reached the 200-step limit" incident was a wall-clock * abort wearing the cap message). */ private buildLoopExitMessage; protected formatProviderError(error: unknown): Error; /** * Memory-safe cache management for model configurations * Implements LRU eviction to prevent memory leaks in long-running processes */ private static evictLRUCacheEntries; /** * Access and refresh cache entry (moves to end for LRU) */ private static accessCacheEntry; /** * Memory-safe cached check for whether maxTokens should be set for the given model * Optimized for streaming performance with LRU eviction to prevent memory leaks */ private shouldSetMaxTokensCached; /** * Memory-safe check if model has maxTokens issues using configuration-based approach * This replaces hardcoded model-specific logic with configurable behavior * Includes LRU caching to avoid repeated configuration lookups during streaming */ private modelHasMaxTokensIssues; /** * Check if Anthropic models are available * @returns Promise indicating if Anthropic support is available */ hasAnthropicSupport(): Promise; /** * @deprecated This method is no longer used. Claude models now use native @anthropic-ai/vertex-sdk * via executeNativeAnthropicStream and executeNativeAnthropicGenerate. */ createAnthropicModel(_modelName: string): Promise; /** * Validate Vertex AI authentication configuration */ private validateVertexAuthentication; /** * Validate Vertex AI project configuration */ private validateVertexProjectConfiguration; /** * Check if the specified region supports Anthropic models */ private checkVertexRegionalSupport; /** * Validate Anthropic model name format and availability */ private validateAnthropicModelName; /** * Analyze Anthropic model creation errors for detailed troubleshooting */ private analyzeAnthropicCreationError; /** * Get detailed troubleshooting steps based on error analysis */ private getAnthropicTroubleshootingSteps; /** * Register a tool with the AI provider * @param name The name of the tool * @param schema The Zod schema defining the tool's parameters * @param description A description of what the tool does * @param handler The function to execute when the tool is called */ registerTool(name: string, schema: ZodType, description: string, handler: (params: Record) => Promise): void; /** * Set the context for tool execution * @param context The context to use for tool execution */ setToolContext(context: Record): void; /** * Get the current tool execution context * @returns The current tool execution context */ getToolContext(): Record; /** * Set the tool executor function for custom tool execution * This method is called by BaseProvider.setupToolExecutor() * @param executor Function to execute tools by name */ setToolExecutor(executor: (toolName: string, params: unknown) => Promise): void; /** * Clear all static caches - useful for testing and memory cleanup * Public method to allow external cache management */ static clearCaches(): void; /** * Get cache statistics for monitoring and debugging */ static getCacheStats(): { modelConfigCacheSize: number; maxTokensCacheSize: number; maxCacheSize: number; cacheAge: { modelConfig: number; maxTokens: number; }; }; /** * Detect image MIME type from buffer */ private detectImageType; /** * Estimate token count from text (simple character-based estimation) */ private estimateTokenCount; /** * Build image parts for multimodal content */ /** * Overrides the BaseProvider's image generation method to implement it for Vertex AI. * Uses REST API approach with google-auth-library for authentication. * Supports PDF input for image generation with gemini-3-pro-image-preview (Nano Banana Pro). * @param options The generation options containing the prompt and optional PDF files. * @returns A promise that resolves to the generation result, including the image data. */ protected executeImageGeneration(options: TextGenerationOptions): Promise; /** * Get model suggestions when a model is not found */ private getModelSuggestions; /** * Generate an embedding for `text` using Vertex via @google/genai. * * Replaces the previous `@ai-sdk/google-vertex` text embedding model * path. Without this, RAG indexing falls through to BaseProvider.embed() * which throws "Embedding generation is not supported by the vertex * provider", and `neurolink rag index --provider=vertex` fails even * though the SDK conceptually supports it. */ embed(text: string, modelName?: string): Promise; /** * Batch-embed an array of strings via Vertex @google/genai. * Mirrors {@link embed} but returns one vector per input string. */ embedMany(texts: string[], modelName?: string): Promise; } export default GoogleVertexProvider; export { GoogleVertexProvider as GoogleVertexAI };