diff --git a/README.md b/README.md index 0f3bb15e..4a4f7c4f 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,23 @@ Copy your Personal Key to replace `your-zilliz-cloud-api-key` in the configurati
-Get OpenAI API Key for embedding model +Get an API Key for embedding model -You need an OpenAI API key for the embedding model. You can get one by signing up at [OpenAI](https://platform.openai.com/api-keys). +You need an API key for the embedding model. Claude Context supports multiple providers: -Your API key will look like this: it always starts with `sk-`. -Copy your key and use it in the configuration examples below as `your-openai-api-key`. +**Option 1: OpenAI** +- Sign up at [OpenAI](https://platform.openai.com/api-keys) +- Your API key will start with `sk-` +- Use as `your-openai-api-key` in configuration + +**Option 2: Azure OpenAI** +- Use your Azure OpenAI resource endpoint and API key +- Requires deployment name instead of model name +- See [Azure OpenAI Documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/) + +**Option 3: Other Providers** +- VoyageAI, Gemini, or Ollama (local) +- See [Provider Configuration Guide](packages/mcp/README.md#embedding-provider-configuration) for details
@@ -519,8 +530,7 @@ Claude Context is a monorepo containing three main packages: - **`@zilliz/claude-context-mcp`**: Model Context Protocol server for AI agent integration ### Supported Technologies - -- **Embedding Providers**: [OpenAI](https://openai.com), [VoyageAI](https://voyageai.com), [Ollama](https://ollama.ai), [Gemini](https://gemini.google.com) +- **Embedding Providers**: [OpenAI](https://openai.com), [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service), [VoyageAI](https://voyageai.com), [Ollama](https://ollama.ai), [Gemini](https://gemini.google.com) - **Vector Databases**: [Milvus](https://milvus.io) or [Zilliz Cloud](https://zilliz.com/cloud)(fully managed vector database as a service) - **Code Splitters**: AST-based splitter (with automatic fallback), LangChain character-based splitter - **Languages**: TypeScript, JavaScript, Python, Java, C++, C#, Go, Rust, PHP, Ruby, Swift, Kotlin, Scala, Markdown diff --git a/docs/getting-started/environment-variables.md b/docs/getting-started/environment-variables.md index d2b813df..4c678db3 100644 --- a/docs/getting-started/environment-variables.md +++ b/docs/getting-started/environment-variables.md @@ -20,10 +20,14 @@ Claude Context supports a global configuration file at `~/.context/.env` to simp ### Embedding Provider | Variable | Description | Default | |----------|-------------|---------| -| `EMBEDDING_PROVIDER` | Provider: `OpenAI`, `VoyageAI`, `Gemini`, `Ollama` | `OpenAI` | +| `EMBEDDING_PROVIDER` | Provider: `OpenAI`, `AzureOpenAI`, `VoyageAI`, `Gemini`, `Ollama` | `OpenAI` | | `EMBEDDING_MODEL` | Embedding model name (works for all providers) | Provider-specific default | | `OPENAI_API_KEY` | OpenAI API key | Required for OpenAI | | `OPENAI_BASE_URL` | OpenAI API base URL (optional, for custom endpoints) | `https://api.openai.com/v1` | +| `AZURE_OPENAI_API_KEY` | Azure OpenAI API key | Required for Azure OpenAI | +| `AZURE_OPENAI_ENDPOINT` | Azure OpenAI endpoint URL | Required for Azure OpenAI | +| `AZURE_OPENAI_DEPLOYMENT_NAME` | Azure deployment name | Required for Azure OpenAI | +| `AZURE_OPENAI_API_VERSION` | Azure API version | `2024-02-01` | | `VOYAGEAI_API_KEY` | VoyageAI API key | Required for VoyageAI | | `GEMINI_API_KEY` | Gemini API key | Required for Gemini | | `GEMINI_BASE_URL` | Gemini API base URL (optional, for custom endpoints) | `https://generativelanguage.googleapis.com/v1beta` | @@ -33,6 +37,8 @@ Claude Context supports a global configuration file at `~/.context/.env` to simp > **Supported Model Names:** > > - OpenAI Models: See `getSupportedModels` in [`openai-embedding.ts`](https://github.com/zilliztech/claude-context/blob/master/packages/core/src/embedding/openai-embedding.ts) for the full list of supported models. +> +> - Azure OpenAI: Uses deployment names instead of model names. Supports the same models as OpenAI (text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002). > > - VoyageAI Models: See `getSupportedModels` in [`voyageai-embedding.ts`](https://github.com/zilliztech/claude-context/blob/master/packages/core/src/embedding/voyageai-embedding.ts) for the full list of supported models. > @@ -67,6 +73,8 @@ Claude Context supports a global configuration file at `~/.context/.env` to simp ## 🚀 Quick Setup ### 1. Create Global Config + +**Option A: OpenAI** ```bash mkdir -p ~/.context cat > ~/.context/.env << 'EOF' @@ -77,6 +85,18 @@ MILVUS_TOKEN=your-zilliz-cloud-api-key EOF ``` +**Option B: Azure OpenAI** +```bash +mkdir -p ~/.context +cat > ~/.context/.env << 'EOF' +EMBEDDING_PROVIDER=AzureOpenAI +AZURE_OPENAI_API_KEY=your-azure-api-key +AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com +AZURE_OPENAI_DEPLOYMENT_NAME=text-embedding-3-small-deployment +MILVUS_TOKEN=your-zilliz-cloud-api-key +EOF +``` + See the [Example File](../../.env.example) for more details. ### 2. Simplified MCP Configuration diff --git a/packages/core/README.md b/packages/core/README.md index 3ea03911..3d187755 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -105,6 +105,7 @@ results.forEach(result => { ## Embedding Providers - **OpenAI Embeddings** (`text-embedding-3-small`, `text-embedding-3-large`, `text-embedding-ada-002`) +- **Azure OpenAI Embeddings** - Same models as OpenAI, deployed on Azure infrastructure - **VoyageAI Embeddings** - High-quality embeddings optimized for code (`voyage-code-3`, `voyage-3.5`, etc.) - **Gemini Embeddings** - Google's embedding models (`gemini-embedding-001`) - **Ollama Embeddings** - Local embedding models via Ollama @@ -190,6 +191,30 @@ interface SemanticSearchResult { ## Examples +### Using Azure OpenAI Embeddings + +```typescript +import { Context, MilvusVectorDatabase, AzureOpenAIEmbedding } from '@zilliz/claude-context-core'; + +// Initialize with Azure OpenAI embedding provider +const embedding = new AzureOpenAIEmbedding({ + deploymentName: 'text-embedding-3-small-deployment', + apiKey: process.env.AZURE_OPENAI_API_KEY || 'your-azure-api-key', + azureEndpoint: process.env.AZURE_OPENAI_ENDPOINT || 'https://your-resource.openai.azure.com', + apiVersion: '2024-02-01' // Optional +}); + +const vectorDatabase = new MilvusVectorDatabase({ + address: process.env.MILVUS_ADDRESS || 'localhost:19530', + token: process.env.MILVUS_TOKEN || '' +}); + +const context = new Context({ + embedding, + vectorDatabase +}); +``` + ### Using VoyageAI Embeddings ```typescript diff --git a/packages/core/src/embedding/azure-openai-embedding.ts b/packages/core/src/embedding/azure-openai-embedding.ts new file mode 100644 index 00000000..0e723aca --- /dev/null +++ b/packages/core/src/embedding/azure-openai-embedding.ts @@ -0,0 +1,256 @@ +import { AzureOpenAI } from 'openai'; +import { Embedding, EmbeddingVector } from './base-embedding'; + +export interface AzureOpenAIEmbeddingConfig { + deploymentName: string; // Azure deployment name (not model name) + apiKey: string; // Azure OpenAI API key + azureEndpoint: string; // Required: Azure endpoint URL + apiVersion?: string; // Optional: defaults to stable version +} + +export class AzureOpenAIEmbedding extends Embedding { + private client: AzureOpenAI; + private config: AzureOpenAIEmbeddingConfig; + private dimension: number = 1536; // Default dimension for text-embedding-3-small + protected maxTokens: number = 8192; // Maximum tokens for OpenAI embedding models + + constructor(config: AzureOpenAIEmbeddingConfig) { + super(); + this.config = config; + + // Validate endpoint format + if (!config.azureEndpoint.startsWith('https://')) { + throw new Error('Azure OpenAI endpoint must start with https://'); + } + + // Initialize Azure OpenAI client with API key authentication + this.client = new AzureOpenAI({ + apiKey: config.apiKey, + apiVersion: config.apiVersion || '2024-02-01', // Use stable version + endpoint: config.azureEndpoint, + }); + } + + async detectDimension(testText: string = "test"): Promise { + const knownModels = AzureOpenAIEmbedding.getSupportedModels(); + + // Try to infer from deployment name if it matches known patterns + // Azure deployment names often include the model name with dashes + for (const [modelName, info] of Object.entries(knownModels)) { + // Check if deployment name contains model pattern (with dashes instead of dots) + const modelPattern = modelName.replace(/\./g, '-'); + if (this.config.deploymentName.toLowerCase().includes(modelPattern)) { + return info.dimension; + } + } + + // Dynamic detection via API call for custom deployments + try { + const processedText = this.preprocessText(testText); + const response = await this.client.embeddings.create({ + model: this.config.deploymentName, // Use deployment name + input: processedText, + encoding_format: 'float', + }); + return response.data[0].embedding.length; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + + // Re-throw authentication errors + if (errorMessage.includes('API key') || errorMessage.includes('unauthorized') || errorMessage.includes('authentication')) { + throw new Error(`Azure OpenAI authentication failed: ${errorMessage}`); + } + + // Handle deployment not found errors + if (errorMessage.includes('deployment') || errorMessage.includes('not found')) { + throw new Error(`Azure OpenAI deployment '${this.config.deploymentName}' not found: ${errorMessage}`); + } + + throw new Error(`Failed to detect dimension for Azure deployment ${this.config.deploymentName}: ${errorMessage}`); + } + } + + async embed(text: string): Promise { + const processedText = this.preprocessText(text); + + // Check if we need to detect dimension + const knownModels = AzureOpenAIEmbedding.getSupportedModels(); + let needsDimensionDetection = true; + + for (const [modelName, info] of Object.entries(knownModels)) { + const modelPattern = modelName.replace(/\./g, '-'); + if (this.config.deploymentName.toLowerCase().includes(modelPattern)) { + this.dimension = info.dimension; + needsDimensionDetection = false; + break; + } + } + + if (needsDimensionDetection && this.dimension === 1536) { + // Only detect if we haven't already and are using default + this.dimension = await this.detectDimension(); + } + + try { + const response = await this.client.embeddings.create({ + model: this.config.deploymentName, // Use deployment name + input: processedText, + encoding_format: 'float', + }); + + // Update dimension from actual response + this.dimension = response.data[0].embedding.length; + + return { + vector: response.data[0].embedding, + dimension: this.dimension + }; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + + // Provide specific error messages for common Azure issues + if (errorMessage.includes('API key') || errorMessage.includes('unauthorized')) { + throw new Error(`Azure OpenAI authentication failed: ${errorMessage}`); + } + + if (errorMessage.includes('deployment') || errorMessage.includes('not found')) { + throw new Error(`Azure OpenAI deployment '${this.config.deploymentName}' not found: ${errorMessage}`); + } + + if (errorMessage.includes('rate limit') || errorMessage.includes('quota')) { + throw new Error(`Azure OpenAI rate limit exceeded: ${errorMessage}`); + } + + throw new Error(`Failed to generate Azure OpenAI embedding: ${errorMessage}`); + } + } + + async embedBatch(texts: string[]): Promise { + const processedTexts = this.preprocessTexts(texts); + + // Check if we need to detect dimension + const knownModels = AzureOpenAIEmbedding.getSupportedModels(); + let needsDimensionDetection = true; + + for (const [modelName, info] of Object.entries(knownModels)) { + const modelPattern = modelName.replace(/\./g, '-'); + if (this.config.deploymentName.toLowerCase().includes(modelPattern)) { + this.dimension = info.dimension; + needsDimensionDetection = false; + break; + } + } + + if (needsDimensionDetection && this.dimension === 1536) { + this.dimension = await this.detectDimension(); + } + + try { + const response = await this.client.embeddings.create({ + model: this.config.deploymentName, // Use deployment name + input: processedTexts, + encoding_format: 'float', + }); + + // Update dimension from actual response + this.dimension = response.data[0].embedding.length; + + return response.data.map((item) => ({ + vector: item.embedding, + dimension: this.dimension + })); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + + // Provide specific error messages for common Azure issues + if (errorMessage.includes('API key') || errorMessage.includes('unauthorized')) { + throw new Error(`Azure OpenAI authentication failed: ${errorMessage}`); + } + + if (errorMessage.includes('deployment') || errorMessage.includes('not found')) { + throw new Error(`Azure OpenAI deployment '${this.config.deploymentName}' not found: ${errorMessage}`); + } + + if (errorMessage.includes('rate limit') || errorMessage.includes('quota')) { + throw new Error(`Azure OpenAI rate limit exceeded: ${errorMessage}`); + } + + throw new Error(`Failed to generate Azure OpenAI batch embeddings: ${errorMessage}`); + } + } + + getDimension(): number { + // Check if deployment name matches known models + const knownModels = AzureOpenAIEmbedding.getSupportedModels(); + + for (const [modelName, info] of Object.entries(knownModels)) { + const modelPattern = modelName.replace(/\./g, '-'); + if (this.config.deploymentName.toLowerCase().includes(modelPattern)) { + return info.dimension; + } + } + + // For custom deployments, return the current dimension + // Note: This may be incorrect until detectDimension() is called + console.warn(`[AzureOpenAIEmbedding] ⚠️ getDimension() called for deployment '${this.config.deploymentName}' - returning ${this.dimension}. Call detectDimension() first for accurate dimension.`); + return this.dimension; + } + + getProvider(): string { + return 'Azure OpenAI'; + } + + /** + * Set deployment name + * @param deploymentName Azure deployment name + */ + async setDeployment(deploymentName: string): Promise { + this.config.deploymentName = deploymentName; + + // Check if this matches a known model + const knownModels = AzureOpenAIEmbedding.getSupportedModels(); + let foundKnownModel = false; + + for (const [modelName, info] of Object.entries(knownModels)) { + const modelPattern = modelName.replace(/\./g, '-'); + if (deploymentName.toLowerCase().includes(modelPattern)) { + this.dimension = info.dimension; + foundKnownModel = true; + break; + } + } + + if (!foundKnownModel) { + // Detect dimension for custom deployment + this.dimension = await this.detectDimension(); + } + } + + /** + * Get client instance (for advanced usage) + */ + getClient(): AzureOpenAI { + return this.client; + } + + /** + * Get list of supported models (these are OpenAI model names, not Azure deployment names) + * Azure deployments can be named anything, but often include the model name + */ + static getSupportedModels(): Record { + return { + 'text-embedding-3-small': { + dimension: 1536, + description: 'High performance and cost-effective embedding model (recommended)' + }, + 'text-embedding-3-large': { + dimension: 3072, + description: 'Highest performance embedding model with larger dimensions' + }, + 'text-embedding-ada-002': { + dimension: 1536, + description: 'Legacy model (use text-embedding-3-small instead)' + } + }; + } +} \ No newline at end of file diff --git a/packages/core/src/embedding/index.ts b/packages/core/src/embedding/index.ts index e6110941..4aede51c 100644 --- a/packages/core/src/embedding/index.ts +++ b/packages/core/src/embedding/index.ts @@ -3,6 +3,7 @@ export * from './base-embedding'; // Implementation class exports export * from './openai-embedding'; +export * from './azure-openai-embedding'; export * from './voyageai-embedding'; export * from './ollama-embedding'; export * from './gemini-embedding'; \ No newline at end of file diff --git a/packages/mcp/README.md b/packages/mcp/README.md index 3591ca78..f9783c30 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -34,7 +34,7 @@ Claude Context MCP supports multiple embedding providers. Choose the one that be > 📋 **Quick Reference**: For a complete list of environment variables and their descriptions, see the [Environment Variables Guide](../../docs/getting-started/environment-variables.md). ```bash -# Supported providers: OpenAI, VoyageAI, Gemini, Ollama +# Supported providers: OpenAI, AzureOpenAI, VoyageAI, Gemini, Ollama EMBEDDING_PROVIDER=OpenAI ``` @@ -67,7 +67,36 @@ See `getSupportedModels` in [`openai-embedding.ts`](https://github.com/zilliztec
-2. VoyageAI Configuration +2. Azure OpenAI Configuration + +Azure OpenAI provides the same high-quality embeddings as OpenAI through your Azure infrastructure. + +```bash +# Required: Your Azure OpenAI configuration +EMBEDDING_PROVIDER=AzureOpenAI +AZURE_OPENAI_API_KEY=your-azure-api-key +AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com +AZURE_OPENAI_DEPLOYMENT_NAME=text-embedding-3-small-deployment + +# Optional: API version (default: 2024-02-01) +AZURE_OPENAI_API_VERSION=2024-02-01 +``` + +**Configuration Requirements:** +- `AZURE_OPENAI_ENDPOINT`: Your Azure OpenAI resource endpoint +- `AZURE_OPENAI_DEPLOYMENT_NAME`: Your deployment name (not model name) +- `AZURE_OPENAI_API_KEY`: Your Azure OpenAI API key + +**Getting Started with Azure OpenAI:** +1. Create an Azure OpenAI resource in [Azure Portal](https://portal.azure.com) +2. Deploy an embedding model (e.g., text-embedding-3-small) +3. Copy your endpoint URL and API key from Azure Portal +4. Use the deployment name you created (not the model name) + +
+ +
+3. VoyageAI Configuration VoyageAI offers specialized code embeddings optimized for programming languages. @@ -92,7 +121,7 @@ See `getSupportedModels` in [`voyageai-embedding.ts`](https://github.com/zillizt
-3. Gemini Configuration +4. Gemini Configuration Google's Gemini provides competitive embeddings with good multilingual support. @@ -120,7 +149,7 @@ See `getSupportedModels` in [`gemini-embedding.ts`](https://github.com/zilliztec
-4. Ollama Configuration (Local/Self-hosted) +5. Ollama Configuration (Local/Self-hosted) Ollama allows you to run embeddings locally without sending data to external services. @@ -275,6 +304,25 @@ Pasting the following configuration into your Cursor `~/.cursor/mcp.json` file i } ``` +**Azure OpenAI Configuration:** +```json +{ + "mcpServers": { + "claude-context": { + "command": "npx", + "args": ["-y", "@zilliz/claude-context-mcp@latest"], + "env": { + "EMBEDDING_PROVIDER": "AzureOpenAI", + "AZURE_OPENAI_API_KEY": "your-azure-api-key", + "AZURE_OPENAI_ENDPOINT": "https://your-resource.openai.azure.com", + "AZURE_OPENAI_DEPLOYMENT_NAME": "text-embedding-3-small-deployment", + "MILVUS_TOKEN": "your-zilliz-cloud-api-key" + } + } + } +} +``` + **VoyageAI Configuration:** ```json diff --git a/packages/mcp/src/config.ts b/packages/mcp/src/config.ts index 428f9474..69e45b27 100644 --- a/packages/mcp/src/config.ts +++ b/packages/mcp/src/config.ts @@ -4,11 +4,16 @@ export interface ContextMcpConfig { name: string; version: string; // Embedding provider configuration - embeddingProvider: 'OpenAI' | 'VoyageAI' | 'Gemini' | 'Ollama'; + embeddingProvider: 'OpenAI' | 'AzureOpenAI' | 'VoyageAI' | 'Gemini' | 'Ollama'; embeddingModel: string; // Provider-specific API keys openaiApiKey?: string; openaiBaseUrl?: string; + // Azure OpenAI configuration + azureOpenaiApiKey?: string; + azureOpenaiEndpoint?: string; + azureOpenaiApiVersion?: string; + azureOpenaiDeploymentName?: string; voyageaiApiKey?: string; geminiApiKey?: string; geminiBaseUrl?: string; @@ -72,6 +77,8 @@ export function getDefaultModelForProvider(provider: string): string { switch (provider) { case 'OpenAI': return 'text-embedding-3-small'; + case 'AzureOpenAI': + return 'text-embedding-3-small-deployment'; // Default deployment name case 'VoyageAI': return 'voyage-code-3'; case 'Gemini': @@ -91,6 +98,11 @@ export function getEmbeddingModelForProvider(provider: string): string { const ollamaModel = envManager.get('OLLAMA_MODEL') || envManager.get('EMBEDDING_MODEL') || getDefaultModelForProvider(provider); console.log(`[DEBUG] 🎯 Ollama model selection: OLLAMA_MODEL=${envManager.get('OLLAMA_MODEL') || 'NOT SET'}, EMBEDDING_MODEL=${envManager.get('EMBEDDING_MODEL') || 'NOT SET'}, selected=${ollamaModel}`); return ollamaModel; + case 'AzureOpenAI': + // For Azure OpenAI, use AZURE_OPENAI_DEPLOYMENT_NAME or EMBEDDING_MODEL + const azureDeployment = envManager.get('AZURE_OPENAI_DEPLOYMENT_NAME') || envManager.get('EMBEDDING_MODEL') || getDefaultModelForProvider(provider); + console.log(`[DEBUG] 🎯 Azure OpenAI deployment selection: AZURE_OPENAI_DEPLOYMENT_NAME=${envManager.get('AZURE_OPENAI_DEPLOYMENT_NAME') || 'NOT SET'}, EMBEDDING_MODEL=${envManager.get('EMBEDDING_MODEL') || 'NOT SET'}, selected=${azureDeployment}`); + return azureDeployment; case 'OpenAI': case 'VoyageAI': case 'Gemini': @@ -110,6 +122,8 @@ export function createMcpConfig(): ContextMcpConfig { console.log(`[DEBUG] OLLAMA_MODEL: ${envManager.get('OLLAMA_MODEL') || 'NOT SET'}`); console.log(`[DEBUG] GEMINI_API_KEY: ${envManager.get('GEMINI_API_KEY') ? 'SET (length: ' + envManager.get('GEMINI_API_KEY')!.length + ')' : 'NOT SET'}`); console.log(`[DEBUG] OPENAI_API_KEY: ${envManager.get('OPENAI_API_KEY') ? 'SET (length: ' + envManager.get('OPENAI_API_KEY')!.length + ')' : 'NOT SET'}`); + console.log(`[DEBUG] AZURE_OPENAI_API_KEY: ${envManager.get('AZURE_OPENAI_API_KEY') ? 'SET (length: ' + envManager.get('AZURE_OPENAI_API_KEY')!.length + ')' : 'NOT SET'}`); + console.log(`[DEBUG] AZURE_OPENAI_ENDPOINT: ${envManager.get('AZURE_OPENAI_ENDPOINT') || 'NOT SET'}`); console.log(`[DEBUG] MILVUS_ADDRESS: ${envManager.get('MILVUS_ADDRESS') || 'NOT SET'}`); console.log(`[DEBUG] NODE_ENV: ${envManager.get('NODE_ENV') || 'NOT SET'}`); @@ -117,11 +131,16 @@ export function createMcpConfig(): ContextMcpConfig { name: envManager.get('MCP_SERVER_NAME') || "Context MCP Server", version: envManager.get('MCP_SERVER_VERSION') || "1.0.0", // Embedding provider configuration - embeddingProvider: (envManager.get('EMBEDDING_PROVIDER') as 'OpenAI' | 'VoyageAI' | 'Gemini' | 'Ollama') || 'OpenAI', + embeddingProvider: (envManager.get('EMBEDDING_PROVIDER') as 'OpenAI' | 'AzureOpenAI' | 'VoyageAI' | 'Gemini' | 'Ollama') || 'OpenAI', embeddingModel: getEmbeddingModelForProvider(envManager.get('EMBEDDING_PROVIDER') || 'OpenAI'), // Provider-specific API keys openaiApiKey: envManager.get('OPENAI_API_KEY'), openaiBaseUrl: envManager.get('OPENAI_BASE_URL'), + // Azure OpenAI configuration + azureOpenaiApiKey: envManager.get('AZURE_OPENAI_API_KEY'), + azureOpenaiEndpoint: envManager.get('AZURE_OPENAI_ENDPOINT'), + azureOpenaiApiVersion: envManager.get('AZURE_OPENAI_API_VERSION'), + azureOpenaiDeploymentName: envManager.get('AZURE_OPENAI_DEPLOYMENT_NAME'), voyageaiApiKey: envManager.get('VOYAGEAI_API_KEY'), geminiApiKey: envManager.get('GEMINI_API_KEY'), geminiBaseUrl: envManager.get('GEMINI_BASE_URL'), @@ -153,6 +172,14 @@ export function logConfigurationSummary(config: ContextMcpConfig): void { console.log(`[MCP] OpenAI Base URL: ${config.openaiBaseUrl}`); } break; + case 'AzureOpenAI': + console.log(`[MCP] Azure OpenAI API Key: ${config.azureOpenaiApiKey ? '✅ Configured' : '❌ Missing'}`); + console.log(`[MCP] Azure OpenAI Endpoint: ${config.azureOpenaiEndpoint || '❌ Missing'}`); + console.log(`[MCP] Azure OpenAI Deployment: ${config.azureOpenaiDeploymentName || config.embeddingModel}`); + if (config.azureOpenaiApiVersion) { + console.log(`[MCP] Azure OpenAI API Version: ${config.azureOpenaiApiVersion}`); + } + break; case 'VoyageAI': console.log(`[MCP] VoyageAI API Key: ${config.voyageaiApiKey ? '✅ Configured' : '❌ Missing'}`); break; @@ -185,12 +212,19 @@ Environment Variables: MCP_SERVER_VERSION Server version Embedding Provider Configuration: - EMBEDDING_PROVIDER Embedding provider: OpenAI, VoyageAI, Gemini, Ollama (default: OpenAI) + EMBEDDING_PROVIDER Embedding provider: OpenAI, AzureOpenAI, VoyageAI, Gemini, Ollama (default: OpenAI) EMBEDDING_MODEL Embedding model name (works for all providers) Provider-specific API Keys: OPENAI_API_KEY OpenAI API key (required for OpenAI provider) OPENAI_BASE_URL OpenAI API base URL (optional, for custom endpoints) + + Azure OpenAI Configuration: + AZURE_OPENAI_API_KEY Azure OpenAI API key (required for AzureOpenAI provider) + AZURE_OPENAI_ENDPOINT Azure OpenAI endpoint URL (required for AzureOpenAI provider) + AZURE_OPENAI_API_VERSION Azure OpenAI API version (optional, default: 2024-02-01) + AZURE_OPENAI_DEPLOYMENT_NAME Azure deployment name (required, alternative to EMBEDDING_MODEL) + VOYAGEAI_API_KEY VoyageAI API key (required for VoyageAI provider) GEMINI_API_KEY Google AI API key (required for Gemini provider) GEMINI_BASE_URL Gemini API base URL (optional, for custom endpoints) @@ -213,6 +247,9 @@ Examples: # Start MCP server with VoyageAI and specific model EMBEDDING_PROVIDER=VoyageAI VOYAGEAI_API_KEY=pa-xxx EMBEDDING_MODEL=voyage-3-large MILVUS_TOKEN=your-token npx @zilliz/claude-context-mcp@latest + # Start MCP server with Azure OpenAI + EMBEDDING_PROVIDER=AzureOpenAI AZURE_OPENAI_API_KEY=xxx AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com AZURE_OPENAI_DEPLOYMENT_NAME=text-embedding-3-small-deployment npx @zilliz/claude-context-mcp@latest + # Start MCP server with Gemini and specific model EMBEDDING_PROVIDER=Gemini GEMINI_API_KEY=xxx EMBEDDING_MODEL=gemini-embedding-001 MILVUS_TOKEN=your-token npx @zilliz/claude-context-mcp@latest diff --git a/packages/mcp/src/embedding.ts b/packages/mcp/src/embedding.ts index 6ebd71a0..76427063 100644 --- a/packages/mcp/src/embedding.ts +++ b/packages/mcp/src/embedding.ts @@ -1,8 +1,8 @@ -import { OpenAIEmbedding, VoyageAIEmbedding, GeminiEmbedding, OllamaEmbedding } from "@zilliz/claude-context-core"; +import { OpenAIEmbedding, AzureOpenAIEmbedding, VoyageAIEmbedding, GeminiEmbedding, OllamaEmbedding } from "@zilliz/claude-context-core"; import { ContextMcpConfig } from "./config.js"; // Helper function to create embedding instance based on provider -export function createEmbeddingInstance(config: ContextMcpConfig): OpenAIEmbedding | VoyageAIEmbedding | GeminiEmbedding | OllamaEmbedding { +export function createEmbeddingInstance(config: ContextMcpConfig): OpenAIEmbedding | AzureOpenAIEmbedding | VoyageAIEmbedding | GeminiEmbedding | OllamaEmbedding { console.log(`[EMBEDDING] Creating ${config.embeddingProvider} embedding instance...`); switch (config.embeddingProvider) { @@ -20,6 +20,30 @@ export function createEmbeddingInstance(config: ContextMcpConfig): OpenAIEmbeddi console.log(`[EMBEDDING] ✅ OpenAI embedding instance created successfully`); return openaiEmbedding; + case 'AzureOpenAI': + if (!config.azureOpenaiEndpoint) { + console.error(`[EMBEDDING] ❌ Azure OpenAI endpoint is required but not provided`); + throw new Error('AZURE_OPENAI_ENDPOINT is required for Azure OpenAI embedding provider'); + } + if (!config.azureOpenaiApiKey) { + console.error(`[EMBEDDING] ❌ Azure OpenAI API key is required but not provided`); + throw new Error('AZURE_OPENAI_API_KEY is required for Azure OpenAI embedding provider'); + } + if (!config.azureOpenaiDeploymentName && !config.embeddingModel) { + console.error(`[EMBEDDING] ❌ Azure OpenAI deployment name is required but not provided`); + throw new Error('AZURE_OPENAI_DEPLOYMENT_NAME or EMBEDDING_MODEL is required for Azure OpenAI embedding provider'); + } + + console.log(`[EMBEDDING] 🔧 Configuring Azure OpenAI with deployment: ${config.azureOpenaiDeploymentName || config.embeddingModel}`); + const azureOpenaiEmbedding = new AzureOpenAIEmbedding({ + deploymentName: config.azureOpenaiDeploymentName || config.embeddingModel, + azureEndpoint: config.azureOpenaiEndpoint, + apiVersion: config.azureOpenaiApiVersion, + apiKey: config.azureOpenaiApiKey, + }); + console.log(`[EMBEDDING] ✅ Azure OpenAI embedding instance created successfully`); + return azureOpenaiEmbedding; + case 'VoyageAI': if (!config.voyageaiApiKey) { console.error(`[EMBEDDING] ❌ VoyageAI API key is required but not provided`); @@ -63,7 +87,7 @@ export function createEmbeddingInstance(config: ContextMcpConfig): OpenAIEmbeddi } } -export function logEmbeddingProviderInfo(config: ContextMcpConfig, embedding: OpenAIEmbedding | VoyageAIEmbedding | GeminiEmbedding | OllamaEmbedding): void { +export function logEmbeddingProviderInfo(config: ContextMcpConfig, embedding: OpenAIEmbedding | AzureOpenAIEmbedding | VoyageAIEmbedding | GeminiEmbedding | OllamaEmbedding): void { console.log(`[EMBEDDING] ✅ Successfully initialized ${config.embeddingProvider} embedding provider`); console.log(`[EMBEDDING] Provider details - Model: ${config.embeddingModel}, Dimension: ${embedding.getDimension()}`); @@ -72,6 +96,9 @@ export function logEmbeddingProviderInfo(config: ContextMcpConfig, embedding: Op case 'OpenAI': console.log(`[EMBEDDING] OpenAI configuration - API Key: ${config.openaiApiKey ? '✅ Provided' : '❌ Missing'}, Base URL: ${config.openaiBaseUrl || 'Default'}`); break; + case 'AzureOpenAI': + console.log(`[EMBEDDING] Azure OpenAI configuration - API Key: ${config.azureOpenaiApiKey ? '✅ Provided' : '❌ Missing'}, Endpoint: ${config.azureOpenaiEndpoint}, Deployment: ${config.azureOpenaiDeploymentName || config.embeddingModel}`); + break; case 'VoyageAI': console.log(`[EMBEDDING] VoyageAI configuration - API Key: ${config.voyageaiApiKey ? '✅ Provided' : '❌ Missing'}`); break; diff --git a/packages/vscode-extension/README.md b/packages/vscode-extension/README.md index 495cb5de..56751fb8 100644 --- a/packages/vscode-extension/README.md +++ b/packages/vscode-extension/README.md @@ -14,7 +14,7 @@ A code indexing and semantic search VSCode extension powered by [Claude Context] - 🔍 **Semantic Search**: Intelligent code search based on semantic understanding, not just keyword matching - 📁 **Codebase Indexing**: Automatically index entire codebase and build semantic vector database - 🎯 **Context Search**: Search related code by selecting code snippets -- 🔧 **Multi-platform Support**: Support for OpenAI, VoyageAI, Gemini, and Ollama as embedding providers +- 🔧 **Multi-platform Support**: Support for OpenAI, Azure OpenAI, VoyageAI, Gemini, and Ollama as embedding providers - 💾 **Vector Storage**: Integrated with Milvus vector database for efficient storage and retrieval ## Requirements @@ -46,6 +46,13 @@ Configure your embedding provider to convert code into semantic vectors. - `OpenAI API key`: Your OpenAI API key for authentication - `Custom API endpoint URL`: Optional custom endpoint (defaults to `https://api.openai.com/v1`) +**Azure OpenAI Configuration:** +- `Embedding Provider`: Select "Azure OpenAI" from the dropdown +- `Deployment name`: Your Azure deployment name (not model name) +- `Azure OpenAI endpoint URL`: Your Azure OpenAI resource endpoint +- `Azure OpenAI API key`: Your Azure API key for authentication +- `API version`: Optional API version (defaults to 2024-02-01) + **Other Supported Providers:** - **Gemini**: Google's state-of-the-art embedding model with Matryoshka representation learning - **VoyageAI**: Alternative embedding provider with competitive performance diff --git a/packages/vscode-extension/src/config/configManager.ts b/packages/vscode-extension/src/config/configManager.ts index ee6adffe..888e5d6d 100644 --- a/packages/vscode-extension/src/config/configManager.ts +++ b/packages/vscode-extension/src/config/configManager.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { OpenAIEmbedding, OpenAIEmbeddingConfig, VoyageAIEmbedding, VoyageAIEmbeddingConfig, OllamaEmbedding, OllamaEmbeddingConfig, GeminiEmbedding, GeminiEmbeddingConfig, MilvusConfig, SplitterType, SplitterConfig, AstCodeSplitter, LangChainCodeSplitter } from '@zilliz/claude-context-core'; +import { OpenAIEmbedding, OpenAIEmbeddingConfig, AzureOpenAIEmbedding, AzureOpenAIEmbeddingConfig, VoyageAIEmbedding, VoyageAIEmbeddingConfig, OllamaEmbedding, OllamaEmbeddingConfig, GeminiEmbedding, GeminiEmbeddingConfig, MilvusConfig, SplitterType, SplitterConfig, AstCodeSplitter, LangChainCodeSplitter } from '@zilliz/claude-context-core'; // Simplified Milvus configuration interface for frontend export interface MilvusWebConfig { @@ -10,6 +10,9 @@ export interface MilvusWebConfig { export type EmbeddingProviderConfig = { provider: 'OpenAI'; config: OpenAIEmbeddingConfig; +} | { + provider: 'AzureOpenAI'; + config: AzureOpenAIEmbeddingConfig; } | { provider: 'VoyageAI'; config: VoyageAIEmbeddingConfig; @@ -61,6 +64,22 @@ const EMBEDDING_PROVIDERS = { model: 'text-embedding-3-small' } }, + 'AzureOpenAI': { + name: 'Azure OpenAI', + class: AzureOpenAIEmbedding, + requiredFields: [ + { name: 'deploymentName', type: 'string', description: 'Azure deployment name', inputType: 'text', required: true }, + { name: 'azureEndpoint', type: 'string', description: 'Azure OpenAI endpoint URL', inputType: 'url', required: true, placeholder: 'https://your-resource.openai.azure.com' }, + { name: 'apiKey', type: 'string', description: 'Azure OpenAI API key', inputType: 'password', required: true } + ] as FieldDefinition[], + optionalFields: [ + { name: 'apiVersion', type: 'string', description: 'API version', inputType: 'text', placeholder: '2024-02-01' } + ] as FieldDefinition[], + defaultConfig: { + deploymentName: 'text-embedding-3-small-deployment', + apiVersion: '2024-02-01' + } + }, 'VoyageAI': { name: 'VoyageAI', class: VoyageAIEmbedding, diff --git a/packages/vscode-extension/src/extension.ts b/packages/vscode-extension/src/extension.ts index 462e282a..d2453695 100644 --- a/packages/vscode-extension/src/extension.ts +++ b/packages/vscode-extension/src/extension.ts @@ -132,7 +132,10 @@ function createContextWithConfig(configManager: ConfigManager): Context { // Create embedding instance if (embeddingConfig) { embedding = ConfigManager.createEmbeddingInstance(embeddingConfig.provider, embeddingConfig.config); - console.log(`Embedding initialized with ${embeddingConfig.provider} (model: ${embeddingConfig.config.model})`); + const modelOrDeployment = embeddingConfig.provider === 'AzureOpenAI' + ? (embeddingConfig.config as any).deploymentName + : (embeddingConfig.config as any).model; + console.log(`Embedding initialized with ${embeddingConfig.provider} (${embeddingConfig.provider === 'AzureOpenAI' ? 'deployment' : 'model'}: ${modelOrDeployment})`); contextConfig.embedding = embedding; } else { console.log('No embedding configuration found'); @@ -193,7 +196,10 @@ function reloadContextConfiguration() { if (embeddingConfig) { const embedding = ConfigManager.createEmbeddingInstance(embeddingConfig.provider, embeddingConfig.config); codeContext.updateEmbedding(embedding); - console.log(`Embedding updated with ${embeddingConfig.provider} (model: ${embeddingConfig.config.model})`); + const modelOrDeployment = embeddingConfig.provider === 'AzureOpenAI' + ? (embeddingConfig.config as any).deploymentName + : (embeddingConfig.config as any).model; + console.log(`Embedding updated with ${embeddingConfig.provider} (${embeddingConfig.provider === 'AzureOpenAI' ? 'deployment' : 'model'}: ${modelOrDeployment})`); } // Update vector database if configuration exists