@mastra/azure-ai-search 0.1.1 → 0.1.2-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ name: mastra-azure-ai-search
3
3
  description: Documentation for @mastra/azure-ai-search. Use when working with @mastra/azure-ai-search APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/azure-ai-search"
6
- version: "0.1.1"
6
+ version: "0.1.2-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.1",
2
+ "version": "0.1.2-alpha.1",
3
3
  "package": "@mastra/azure-ai-search",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -18,7 +18,7 @@ The `AzureAISearchVector` class provides vector search using [Azure AI Search](h
18
18
 
19
19
  **clientOptions** (`SearchClientOptions`): Additional options passed to the underlying SearchClient/SearchIndexClient, such as additionalPolicies for proxies, custom headers, or retry behavior.
20
20
 
21
- **autoIndexMetadata** (`boolean`): Add a filterable field to the index the first time a top-level string, number, or boolean metadata key is seen in upsert() or updateVector(). Azure AI Search can only filter on declared fields, so this is required for Memory semantic recall (which filters by thread\_id and resource\_id) unless you declare those keys via metadataIndexes. Set to false to manage the schema yourself. (Default: `true`)
21
+ **autoIndexMetadata** (`boolean`): Add a filterable field to the index the first time a top-level string, number, or boolean metadata key is seen in upsert() or updateVector(). Azure AI Search can only filter on declared fields, so this is required for Memory semantic recall (which filters by thread_id and resource_id) unless you declare those keys via metadataIndexes. Set to false to manage the schema yourself. (Default: `true`)
22
22
 
23
23
  ```typescript
24
24
  import { AzureAISearchVector } from '@mastra/azure-ai-search'
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _azure_search_documents = require("@azure/search-documents");
3
3
  let _mastra_core_error = require("@mastra/core/error");
4
4
  let _mastra_core_vector = require("@mastra/core/vector");
5
- //#region src/vector/filter.ts
5
+ // src/vector/filter.ts
6
6
  /**
7
7
  * An OData predicate that no document can satisfy. Used wherever a filter is
8
8
  * syntactically valid but has nothing it could match (`$or: []`, `$in: []`,
@@ -117,8 +117,7 @@ var AzureAISearchFilterTranslator = class {
117
117
  return field;
118
118
  }
119
119
  };
120
- //#endregion
121
- //#region src/vector/index.ts
120
+ // src/vector/index.ts
122
121
  /**
123
122
  * Azure AI Search document keys may only contain letters, digits, `_`, `-` and `=`.
124
123
  * IDs that use anything else (e.g. `urn:uuid:...`, paths, emails) are base64url
@@ -1204,7 +1203,6 @@ var AzureAISearchVector = class AzureAISearchVector extends _mastra_core_vector.
1204
1203
  });
1205
1204
  }
1206
1205
  };
1207
- //#endregion
1208
1206
  exports.AzureAISearchFilterTranslator = AzureAISearchFilterTranslator;
1209
1207
  exports.AzureAISearchVector = AzureAISearchVector;
1210
1208
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["MastraVector","SearchIndexClient","AzureKeyCredential","SearchClient","MastraError","ErrorDomain","ErrorCategory"],"sources":["../src/vector/filter.ts","../src/vector/index.ts"],"sourcesContent":["import type { VectorFilter } from '@mastra/core/vector/filter';\n\n/**\n * Metadata filter accepted by `@mastra/azure-ai-search`.\n *\n * This is the standard Mastra filter shape (`$eq`, `$ne`, `$gt`, `$gte`,\n * `$lt`, `$lte`, `$in`, `$nin`, `$exists`, `$and`, `$or`, `$not`), which the\n * translator turns into an Azure AI Search OData `$filter` expression. Raw\n * OData is intentionally not accepted: the same filter selects documents for\n * `updateVector` and `deleteVectors`, so every predicate is built from\n * validated field names and escaped literals.\n */\nexport type AzureAISearchVectorFilter = VectorFilter;\n\n/**\n * An OData predicate that no document can satisfy. Used wherever a filter is\n * syntactically valid but has nothing it could match (`$or: []`, `$in: []`,\n * `field: []`). Returning `undefined` there would drop the filter entirely and\n * match every document, which is the wrong direction for a delete or update.\n * OData requires one side of a comparison to be a field, so this compares the\n * always-present key field against itself.\n */\nconst MATCH_NONE = \"(id eq '__mastra_none__' and id ne '__mastra_none__')\";\n\n/**\n * Translates Mastra vector filters to Azure AI Search OData filter syntax\n */\nexport class AzureAISearchFilterTranslator {\n /**\n * Translates a filter object to OData filter string\n * @param filter - The filter to translate\n * @returns OData filter string or undefined if no filter\n */\n translate(filter?: AzureAISearchVectorFilter): string | undefined {\n if (!filter) {\n return undefined;\n }\n\n const translated = this.translateMastraFilter(filter as Record<string, any>).trim();\n return translated.length > 0 ? translated : undefined;\n }\n\n private translateMastraFilter(filter: Record<string, any>): string {\n const conditions: string[] = [];\n\n for (const [key, value] of Object.entries(filter)) {\n if (key === '$and' && Array.isArray(value)) {\n // An empty $and is vacuously true, so it contributes no clause.\n const andConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n if (andConditions.length > 0) {\n conditions.push(`(${andConditions.join(' and ')})`);\n }\n continue;\n }\n\n if (key === '$or' && Array.isArray(value)) {\n const orConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n conditions.push(orConditions.length > 0 ? `(${orConditions.join(' or ')})` : MATCH_NONE);\n continue;\n }\n\n if (key === '$not' && typeof value === 'object' && value !== null) {\n const notCondition = this.translateMastraFilter(value);\n if (notCondition) {\n conditions.push(`not (${notCondition})`);\n }\n continue;\n }\n\n if (key.startsWith('$')) {\n throw new Error(`Unsupported filter operator '${key}'. Azure AI Search supports $and, $or, and $not.`);\n }\n\n conditions.push(...this.translateMastraFieldCondition(key, value));\n }\n\n return conditions.join(' and ');\n }\n\n private translateMastraFieldCondition(field: string, value: any): string[] {\n if (Array.isArray(value)) {\n return [this.formatInClause(field, value)];\n }\n\n if (value === null || value === undefined || typeof value !== 'object' || value instanceof Date) {\n return [`${this.escapeFieldName(field)} eq ${this.formatValue(value)}`];\n }\n\n const conditions: string[] = [];\n for (const [operator, operatorValue] of Object.entries(value)) {\n switch (operator) {\n case '$eq':\n conditions.push(`${this.escapeFieldName(field)} eq ${this.formatValue(operatorValue)}`);\n break;\n case '$ne':\n conditions.push(`${this.escapeFieldName(field)} ne ${this.formatValue(operatorValue)}`);\n break;\n case '$gt':\n conditions.push(`${this.escapeFieldName(field)} gt ${this.formatValue(operatorValue)}`);\n break;\n case '$gte':\n conditions.push(`${this.escapeFieldName(field)} ge ${this.formatValue(operatorValue)}`);\n break;\n case '$lt':\n conditions.push(`${this.escapeFieldName(field)} lt ${this.formatValue(operatorValue)}`);\n break;\n case '$lte':\n conditions.push(`${this.escapeFieldName(field)} le ${this.formatValue(operatorValue)}`);\n break;\n case '$in':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$in on field '${field}' requires an array`);\n }\n conditions.push(this.formatInClause(field, operatorValue));\n break;\n case '$nin':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$nin on field '${field}' requires an array`);\n }\n // \"not in nothing\" is true for every document, so it adds no clause.\n if (operatorValue.length > 0) {\n conditions.push(`not ${this.formatInClause(field, operatorValue)}`);\n }\n break;\n case '$exists':\n conditions.push(`${this.escapeFieldName(field)} ${operatorValue ? 'ne' : 'eq'} null`);\n break;\n case '$not': {\n const negatedConditions = this.translateMastraFieldCondition(field, operatorValue);\n if (negatedConditions.length > 0) {\n conditions.push(`not (${negatedConditions.join(' and ')})`);\n }\n break;\n }\n default:\n throw new Error(\n `Unsupported filter operator '${operator}' on field '${field}'. Azure AI Search supports $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $not.`,\n );\n }\n }\n return conditions;\n }\n\n /**\n * Builds a membership check as an OR-chain of equality comparisons.\n * OData's `in` keyword is not a real operator in Azure AI Search's filter\n * syntax (it only exists as the `search.in()` function, which needs its own\n * comma-escaping for values that may contain the separator), so membership\n * is expressed the portable way: `(field eq v1 or field eq v2 or ...)`.\n * An empty set can match nothing.\n */\n private formatInClause(field: string, values: any[]): string {\n const escapedField = this.escapeFieldName(field);\n if (values.length === 0) {\n return MATCH_NONE;\n }\n return `(${values.map(v => `${escapedField} eq ${this.formatValue(v)}`).join(' or ')})`;\n }\n\n private formatValue(value: any): string {\n if (typeof value === 'string') {\n // Escape single quotes in strings\n const escapedValue = value.replace(/'/g, \"''\");\n return `'${escapedValue}'`;\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'boolean') {\n return value.toString();\n }\n\n if (value === null || value === undefined) {\n return 'null';\n }\n\n return String(value);\n }\n\n private escapeFieldName(field: string): string {\n // Azure AI Search OData uses unquoted field paths (e.g., Address/City)\n // Validate field names to prevent OData injection\n if (!/^[a-zA-Z_][\\w/]*$/.test(field)) {\n throw new Error(`Invalid field name for OData filter: '${field}'`);\n }\n return field;\n }\n}\n","import type { TokenCredential } from '@azure/core-auth';\nimport type {\n VectorQuery,\n VectorSearchOptions,\n SemanticSearchOptions,\n SearchRequestOptions,\n VectorizedQuery,\n SearchClientOptions,\n} from '@azure/search-documents';\nimport { SearchClient, SearchIndexClient, AzureKeyCredential } from '@azure/search-documents';\nimport { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';\nimport type {\n CreateIndexParams,\n DeleteIndexParams,\n DeleteVectorParams,\n DescribeIndexParams,\n IndexStats,\n QueryResult,\n QueryVectorParams,\n UpdateVectorParams,\n UpsertVectorParams,\n} from '@mastra/core/vector';\nimport { MastraVector } from '@mastra/core/vector';\nimport type { AzureAISearchVectorFilter } from './filter';\nimport { AzureAISearchFilterTranslator } from './filter';\n\n/**\n * Configuration options for Azure AI Search vector store\n */\nexport interface AzureAISearchVectorOptions {\n /** The endpoint URL of your Azure AI Search service */\n endpoint: string;\n /** Authentication credential - either API key or Azure credential */\n credential: string | AzureKeyCredential | TokenCredential;\n /** API version (optional, defaults to latest) */\n apiVersion?: string;\n /**\n * Additional options for SearchClient (optional)\n * Use this to pass custom policies like AXET proxy, retry options, etc.\n *\n * @example\n * ```typescript\n * clientOptions: {\n * additionalPolicies: [{\n * position: 'perCall',\n * policy: createAxetProxyPolicy({ ... })\n * }]\n * }\n * ```\n */\n clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n /**\n * Automatically add a filterable field to the index the first time a top-level\n * string/number/boolean metadata key is seen in `upsert`/`updateVector`.\n *\n * Azure AI Search can only filter on fields declared in the index schema and has\n * no JSON-path filtering, so without this, `query({ filter: { thread_id } })` on a\n * key that was never declared via `metadataIndexes` fails with HTTP 400. Mastra\n * Memory relies on filtering by `thread_id`/`resource_id` without declaring them.\n *\n * Field type is inferred from the first value seen. Keys whose names are not valid\n * Azure field names (must match `^[A-Za-z][A-Za-z0-9_]*$`), or whose values are\n * arrays/objects/null, stay in the JSON `metadata` blob only and are not filterable.\n *\n * Defaults to `true`. Set to `false` to require explicit `metadataIndexes`.\n */\n autoIndexMetadata?: boolean;\n}\n\n/**\n * Azure AI Search document keys may only contain letters, digits, `_`, `-` and `=`.\n * IDs that use anything else (e.g. `urn:uuid:...`, paths, emails) are base64url\n * encoded behind a marker prefix and decoded back on every read path.\n */\nconst SAFE_DOCUMENT_KEY = /^[A-Za-z0-9_\\-=]+$/;\nconst ENCODED_KEY_PREFIX = 'b64-';\n\nfunction encodeDocumentKey(id: string): string {\n if (SAFE_DOCUMENT_KEY.test(id) && !id.startsWith(ENCODED_KEY_PREFIX)) {\n return id;\n }\n return ENCODED_KEY_PREFIX + Buffer.from(id, 'utf8').toString('base64url');\n}\n\nfunction decodeDocumentKey(key: string): string {\n if (!key.startsWith(ENCODED_KEY_PREFIX)) {\n return key;\n }\n return Buffer.from(key.slice(ENCODED_KEY_PREFIX.length), 'base64url').toString('utf8');\n}\n\n/** Azure AI Search field naming rules (letters/digits/underscore, must start with a letter, max 128 chars). */\nconst AZURE_FIELD_NAME = /^[A-Za-z][A-Za-z0-9_]{0,127}$/;\n\nfunction edmTypeForValue(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return 'Edm.String';\n case 'number':\n return Number.isFinite(value) ? 'Edm.Double' : undefined;\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return undefined;\n }\n}\n\nfunction valueMatchesEdmType(value: unknown, edmType: string | undefined): boolean {\n switch (edmType) {\n case 'Edm.String':\n return typeof value === 'string';\n case 'Edm.Double':\n case 'Edm.Int32':\n case 'Edm.Int64':\n return typeof value === 'number' && Number.isFinite(value);\n case 'Edm.Boolean':\n return typeof value === 'boolean';\n default:\n return false;\n }\n}\n\n/**\n * Azure AI Search document structure for vector storage\n */\ninterface AzureAISearchDocument {\n /** Unique identifier for the document */\n id: string;\n /** Vector embedding */\n vector: number[];\n /** Metadata associated with the document (stored as JSON string) */\n metadata: string;\n /** Optional content field */\n content?: string;\n}\n\n/**\n * Mapping of Mastra metrics to Azure AI Search vector similarity functions\n */\nconst METRIC_MAPPING = {\n cosine: 'cosine',\n euclidean: 'euclidean',\n dotproduct: 'dotProduct',\n} as const;\n\nexport type AzureAISearchQueryVectorParams = QueryVectorParams<AzureAISearchVectorFilter>;\n\ntype AzureAISearchUpsertParams = UpsertVectorParams & { deleteFilter?: AzureAISearchVectorFilter };\ntype AzureAISearchUpdateParams = UpdateVectorParams & { filter?: AzureAISearchVectorFilter };\ntype AzureAISearchDeleteVectorsParams = {\n indexName: string;\n ids?: string[];\n filter?: AzureAISearchVectorFilter;\n};\n\ninterface IndexSchema {\n vectorFieldName: string;\n dimension: number | undefined;\n fields: Map<string, IndexFieldCapabilities>;\n}\n\ntype IndexFieldCapabilities = {\n type?: string;\n};\n\nconst DEFAULT_DOCUMENT_FIELDS = new Set(['id', 'metadata', 'content']);\n\n/**\n * Extended index creation parameters for Azure AI Search specific features\n */\nexport interface AzureAISearchCreateIndexParams extends CreateIndexParams {\n /** Name of the vector field (defaults to 'vector') */\n vectorField?: string;\n /** Additional fields to include in the index schema */\n additionalFields?: Array<{\n name: string;\n type: string;\n searchable?: boolean;\n filterable?: boolean;\n retrievable?: boolean;\n sortable?: boolean;\n facetable?: boolean;\n key?: boolean;\n }>;\n /**\n * Metadata keys that should also be created as explicit filterable Azure AI Search fields.\n * A plain string declares a field as `Edm.String` (backward-compatible default). To filter\n * on a numeric or boolean metadata value with the correct Azure field type — required for\n * numeric comparisons like $gt/$gte/$lt/$lte to work, since Azure rejects an unquoted numeric\n * literal against an Edm.String field — pass `{ name, type }` instead.\n */\n metadataIndexes?: Array<string | { name: string; type: 'string' | 'number' | 'boolean' }>;\n /** HNSW algorithm parameters */\n hnswParameters?: {\n m?: number;\n efConstruction?: number;\n efSearch?: number;\n };\n /** Semantic search configuration */\n semanticConfig?: {\n name?: string;\n prioritizedFields?: {\n /** Single title field for semantic ranking */\n titleField?: { fieldName: string };\n /** Content fields for semantic ranking (renamed from contentFields) */\n prioritizedContentFields?: Array<{ fieldName: string }>;\n /** Keywords fields for semantic ranking (renamed from keywordsFields) */\n prioritizedKeywordsFields?: Array<{ fieldName: string }>;\n };\n };\n /**\n * Enable vector compression (quantization) on the index's vector field.\n * Required for the `oversampling` query parameter to have any effect —\n * Azure AI Search only allows oversampling when the vector field has a\n * compression configured, since oversampling compensates for the recall\n * lost to compression.\n */\n compression?: {\n /** Compression kind. Defaults to 'scalarQuantization'. */\n kind?: 'scalarQuantization' | 'binaryQuantization';\n };\n}\n\n/**\n * Extended query parameters for Azure AI Search advanced features\n */\nexport interface AzureAISearchAdvancedQueryParams extends AzureAISearchQueryVectorParams {\n /** Enable semantic search capabilities */\n useSemanticSearch?: boolean;\n /** Semantic search configuration */\n semanticOptions?: {\n /** Name of semantic configuration in the index */\n configurationName?: string;\n /** Separate query for semantic reranking */\n semanticQuery?: string;\n /** Enable answer extraction from documents */\n answers?: boolean;\n /** Enable caption extraction from documents */\n captions?: boolean;\n /** Maximum wait time for semantic processing (ms) */\n maxWaitTime?: number;\n };\n /** Use exhaustive k-NN search for exact results */\n exhaustiveSearch?: boolean;\n /** Oversampling factor for compressed vectors */\n oversampling?: number;\n /** Relative weight for this vector query in hybrid scenarios */\n weight?: number;\n /** Query type: simple, full, or semantic */\n queryType?: 'simple' | 'full' | 'semantic';\n /**\n * Combine a full-text query with the vector query for hybrid search.\n * Runs as native Azure AI Search hybrid search (BM25 full-text + vector,\n * fused via Reciprocal Rank Fusion) — no vectorizer needs to be configured\n * on the index, unlike Azure's server-side query vectorization.\n */\n textVectorization?: {\n /** Text to search for (BM25 full-text search term) */\n text: string;\n /** Searchable text fields to match against. Defaults to the index's default searchable fields (e.g. content). */\n fields?: string[];\n };\n /** Multiple vector queries for hybrid search */\n additionalVectorQueries?: Array<{\n vector: number[];\n fields?: string[];\n weight?: number;\n kNearestNeighborsCount?: number;\n }>;\n /** Vector filter mode: apply before or after vector search */\n filterMode?: 'preFilter' | 'postFilter';\n}\n\n/**\n * Azure AI Search vector store implementation for Mastra\n *\n * This implementation provides vector storage and similarity search capabilities\n * using Azure AI Search's vector search features.\n *\n * @example\n * ```typescript\n * const azureVector = new AzureAISearchVector({\n * id: 'azure-search-vectors',\n * endpoint: 'https://your-service.search.windows.net',\n * credential: 'your-api-key'\n * });\n *\n * // Create an index\n * await azureVector.createIndex({\n * indexName: 'products',\n * dimension: 1536,\n * metric: 'cosine'\n * });\n *\n * // Insert vectors\n * const ids = await azureVector.upsert({\n * indexName: 'products',\n * vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],\n * metadata: [{ category: 'electronics' }, { category: 'books' }]\n * });\n *\n * // Search vectors\n * const results = await azureVector.query({\n * indexName: 'products',\n * queryVector: [0.1, 0.2, ...],\n * topK: 5,\n * filter: { eq: { category: 'electronics' } }\n * });\n * ```\n */\nexport class AzureAISearchVector extends MastraVector<AzureAISearchVectorFilter> {\n private endpoint: string;\n private credential: string | AzureKeyCredential | TokenCredential;\n private apiVersion?: string;\n private clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n private indexClient: SearchIndexClient;\n private searchClients: Map<string, SearchClient<AzureAISearchDocument>> = new Map();\n private autoIndexMetadata: boolean;\n /**\n * Serializes schema updates per index within this process. `createOrUpdateIndex`\n * is last-writer-wins, so two concurrent upserts each adding a different new\n * metadata field would otherwise clobber each other's field.\n */\n private schemaUpdateQueues: Map<string, Promise<void>> = new Map();\n\n /**\n * Azure AI Search rejects indexing requests containing more than 1,000 documents\n * (and any request larger than 16 MB). Chunk large upload/merge/delete calls to\n * stay within these per-request limits.\n */\n private static readonly INDEXING_BATCH_SIZE = 1000;\n\n constructor({\n id,\n endpoint,\n credential,\n apiVersion,\n clientOptions,\n autoIndexMetadata = true,\n }: AzureAISearchVectorOptions & { id: string }) {\n super({ id });\n\n this.endpoint = endpoint;\n this.credential = credential;\n this.apiVersion = apiVersion;\n this.clientOptions = clientOptions;\n this.autoIndexMetadata = autoIndexMetadata;\n\n // Initialize the index client for managing indexes\n this.indexClient = new SearchIndexClient(\n endpoint,\n typeof credential === 'string' ? new AzureKeyCredential(credential) : credential,\n {\n apiVersion,\n ...clientOptions, // Apply client options to index client as well\n },\n );\n }\n\n /**\n * Static factory method for easier instantiation with connection string\n */\n static fromConnectionString(connectionString: string, options?: { id?: string; apiVersion?: string }) {\n const url = new URL(connectionString);\n const endpoint = url.origin;\n const apiKey = url.searchParams.get('api-key') || url.searchParams.get('key');\n\n if (!apiKey) {\n throw new Error('API key not found in connection string');\n }\n\n return new AzureAISearchVector({\n id: options?.id || 'azure-ai-search',\n endpoint,\n credential: apiKey,\n apiVersion: options?.apiVersion,\n });\n }\n\n /**\n * Gets or creates a search client for a specific index\n */\n private getSearchClient(indexName: string): SearchClient<AzureAISearchDocument> {\n if (!this.searchClients.has(indexName)) {\n const client = new SearchClient<AzureAISearchDocument>(\n this.endpoint,\n indexName,\n typeof this.credential === 'string' ? new AzureKeyCredential(this.credential) : this.credential,\n {\n apiVersion: this.apiVersion,\n ...this.clientOptions, // Merge custom client options\n },\n );\n this.searchClients.set(indexName, client);\n }\n return this.searchClients.get(indexName)!;\n }\n\n /**\n * Runs an indexing operation (upload/merge/delete) in batches that respect\n * Azure AI Search's 1,000-document per-request limit, aggregating the\n * per-document results across all batches.\n */\n private async runBatchedIndexing<R extends { succeeded: boolean; key: string; errorMessage?: string }>(\n documents: unknown[],\n operation: (batch: unknown[]) => Promise<{ results: R[] }>,\n ): Promise<R[]> {\n const results: R[] = [];\n for (let i = 0; i < documents.length; i += AzureAISearchVector.INDEXING_BATCH_SIZE) {\n const batch = documents.slice(i, i + AzureAISearchVector.INDEXING_BATCH_SIZE);\n const { results: batchResults } = await this.retryWhileSchemaPropagates(() => operation(batch));\n results.push(...batchResults);\n }\n return results;\n }\n\n /**\n * A field added with `createOrUpdateIndex` is not immediately visible to the\n * indexing endpoint; an upload issued right after can be rejected with\n * \"The property 'x' does not exist on type 'search.documentFields'\". Retry that\n * specific error briefly while the schema change propagates.\n */\n private async retryWhileSchemaPropagates<T>(operation: () => Promise<T>): Promise<T> {\n const maxAttempts = 20;\n const delayMs = 500;\n for (let attempt = 1; ; attempt++) {\n try {\n return await operation();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const schemaLag = /does not exist on type 'search\\.documentFields'/.test(message);\n if (!schemaLag || attempt >= maxAttempts) {\n throw error;\n }\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n }\n\n /**\n * Reads the index definition once and derives everything a write path needs\n * from it: the vector field name, its dimension, and per-field capabilities.\n * `@azure/search-documents` does not cache `getIndex`, so callers that need\n * more than one of these must share a single read.\n */\n private async readIndexSchema(indexName: string): Promise<IndexSchema> {\n const index = await this.indexClient.getIndex(indexName);\n return this.schemaFromIndex(index);\n }\n\n private schemaFromIndex(index: { fields?: unknown[] }): IndexSchema {\n const fields = new Map<string, IndexFieldCapabilities>();\n let vectorFieldName = 'vector';\n let dimension: number | undefined;\n\n for (const raw of index.fields ?? []) {\n const field = raw as { name: string; type: string; dimensions?: number; vectorSearchDimensions?: number };\n fields.set(field.name, { type: field.type });\n const dims = field.dimensions ?? field.vectorSearchDimensions;\n if (dimension === undefined && field.type === 'Collection(Edm.Single)' && dims) {\n vectorFieldName = field.name;\n dimension = dims;\n }\n }\n\n return { vectorFieldName, dimension, fields };\n }\n\n /**\n * Detects the vector field name in an existing index\n * Falls back to 'vector' for backward compatibility\n */\n private async getVectorFieldName(indexName: string): Promise<string> {\n try {\n return (await this.readIndexSchema(indexName)).vectorFieldName;\n } catch {\n // If we can't determine the vector field name, fall back to 'vector' for backward compatibility\n return 'vector';\n }\n }\n\n private getMetadataIndexFields(\n metadataIndexes: NonNullable<AzureAISearchCreateIndexParams['metadataIndexes']>,\n additionalFields: AzureAISearchCreateIndexParams['additionalFields'],\n ) {\n const edmTypeFor = (type?: 'string' | 'number' | 'boolean'): string => {\n switch (type) {\n case 'number':\n return 'Edm.Double';\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return 'Edm.String';\n }\n };\n\n const reservedFieldNames = new Set(['id', 'metadata', 'content', 'vector']);\n return metadataIndexes\n .map(entry => (typeof entry === 'string' ? { name: entry, type: 'string' as const } : entry))\n .filter(\n entry => !reservedFieldNames.has(entry.name) && !additionalFields?.some(field => field.name === entry.name),\n )\n .map(entry => ({\n name: entry.name,\n type: edmTypeFor(entry.type),\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n }));\n }\n\n private async ensureExistingIndexFields({\n indexName,\n fields,\n }: {\n indexName: string;\n fields: Array<Record<string, any>>;\n }): Promise<void> {\n if (fields.length === 0) {\n return;\n }\n\n const previous = this.schemaUpdateQueues.get(indexName) ?? Promise.resolve();\n const run = previous\n .catch(() => {})\n .then(async () => {\n // Re-read inside the lock so we merge onto whatever the previous update wrote.\n const existingIndex = (await this.indexClient.getIndex(indexName)) as any;\n const existingFieldNames = new Set((existingIndex.fields ?? []).map((field: any) => field.name));\n const missingFields = fields.filter(field => !existingFieldNames.has(field.name));\n\n if (missingFields.length === 0) {\n return;\n }\n\n await (this.indexClient as any).createOrUpdateIndex({\n ...existingIndex,\n fields: [...(existingIndex.fields ?? []), ...missingFields],\n });\n });\n this.schemaUpdateQueues.set(indexName, run);\n try {\n await run;\n } finally {\n if (this.schemaUpdateQueues.get(indexName) === run) {\n this.schemaUpdateQueues.delete(indexName);\n }\n }\n }\n\n /**\n * Adds a filterable field for every top-level scalar metadata key that the index\n * does not yet have, so that `filter: { key: value }` works without the caller\n * declaring the key up front. Mutates `fields` so the subsequent document build\n * writes the typed column. No-op when `autoIndexMetadata` is false.\n */\n private async ensureMetadataFields({\n indexName,\n metadataList,\n vectorFieldName,\n fields,\n }: {\n indexName: string;\n metadataList: Array<Record<string, any> | undefined>;\n vectorFieldName: string;\n fields: Map<string, IndexFieldCapabilities>;\n }): Promise<void> {\n if (!this.autoIndexMetadata) {\n return;\n }\n\n const missing = new Map<string, string>();\n for (const metadata of metadataList) {\n if (!metadata) continue;\n for (const [key, value] of Object.entries(metadata)) {\n if (fields.has(key) || missing.has(key)) continue;\n if (DEFAULT_DOCUMENT_FIELDS.has(key) || key === vectorFieldName) continue;\n // Names starting with \"azureSearch\" are reserved by the service.\n if (!AZURE_FIELD_NAME.test(key) || key.startsWith('azureSearch')) continue;\n const edmType = edmTypeForValue(value);\n if (!edmType) continue;\n missing.set(key, edmType);\n }\n }\n\n if (missing.size === 0) {\n return;\n }\n\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...missing].map(([name, type]) => ({\n name,\n type,\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n })),\n });\n\n // Another writer may have declared the field with a different type; re-read\n // the authoritative schema rather than trusting our inferred types.\n const refreshed = (await this.readIndexSchema(indexName)).fields;\n for (const [name, capability] of refreshed) {\n fields.set(name, capability);\n }\n }\n\n private buildDocumentFromMetadata({\n id,\n vector,\n vectorFieldName,\n metadata = {},\n fields,\n writeMetadata = true,\n }: {\n id: string;\n vector?: number[];\n vectorFieldName: string;\n metadata?: Record<string, any>;\n fields: Map<string, IndexFieldCapabilities>;\n writeMetadata?: boolean;\n }): Record<string, any> {\n const doc: Record<string, any> = { id };\n\n if (writeMetadata) {\n doc.metadata = JSON.stringify(metadata);\n }\n\n if (vector) {\n doc[vectorFieldName] = vector;\n }\n\n // `content` is derived from metadata, so whenever the metadata blob is\n // (re)written the column must follow it; otherwise a merge would keep a\n // stale value from the previous document.\n if (typeof metadata.content === 'string') {\n doc.content = metadata.content;\n } else if (writeMetadata) {\n doc.content = '';\n }\n\n for (const [fieldName, field] of fields.entries()) {\n if (DEFAULT_DOCUMENT_FIELDS.has(fieldName) || fieldName === vectorFieldName) {\n continue;\n }\n\n if (field.type === 'Collection(Edm.Single)') {\n continue;\n }\n\n // Only write the typed column when the JS value matches the column's Edm type.\n // Azure rejects the whole document otherwise (e.g. number into Edm.String:\n // \"Cannot convert the literal '0' to the expected type 'Edm.String'\"). The\n // JSON `metadata` blob remains the source of truth on read either way.\n if (Object.prototype.hasOwnProperty.call(metadata, fieldName)) {\n doc[fieldName] = valueMatchesEdmType(metadata[fieldName], field.type) ? metadata[fieldName] : null;\n }\n }\n\n return doc;\n }\n\n /**\n * Creates a new vector search index with the specified configuration\n *\n * @param params - Index creation parameters (supports both basic Mastra interface and Azure AI Search extended options)\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createIndex(params: CreateIndexParams | AzureAISearchCreateIndexParams): Promise<void> {\n const {\n indexName,\n dimension,\n metric = 'cosine',\n vectorField = 'vector',\n additionalFields = [],\n metadataIndexes = [],\n hnswParameters = {},\n semanticConfig,\n compression,\n } = params as AzureAISearchCreateIndexParams;\n\n if (!Number.isInteger(dimension) || dimension <= 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_INVALID_DIMENSION',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Dimension must be a positive integer',\n details: { indexName, dimension },\n });\n }\n\n try {\n const similarityFunction = METRIC_MAPPING[metric as keyof typeof METRIC_MAPPING];\n\n // Vector field configuration (customizable name).\n // Both `retrievable` and `hidden` are set: some API versions key retrievability\n // off `retrievable`, newer ones off `hidden` (inverted) — the service otherwise\n // silently defaults new vector fields to hidden/non-retrievable and `$select`ing\n // them for `includeVector` fails with \"'vector' is not a retrievable field\".\n const vectorFieldConfig = {\n name: vectorField,\n type: 'Collection(Edm.Single)',\n searchable: true,\n retrievable: true,\n hidden: false,\n vectorSearchDimensions: dimension,\n vectorSearchProfileName: 'vector-profile',\n };\n\n // Core default fields (aligned with other Mastra vector stores)\n const defaultFields = [\n {\n name: 'id',\n type: 'Edm.String',\n key: true,\n filterable: true,\n // Sortable so filter-based lookups can page past Azure's 100,000 $skip\n // ceiling using a stable ordered range scan (see findIdsByFilter).\n sortable: true,\n facetable: false,\n searchable: false,\n },\n vectorFieldConfig,\n {\n name: 'metadata',\n type: 'Edm.String',\n searchable: false,\n filterable: true,\n sortable: false,\n facetable: false,\n },\n {\n name: 'content',\n type: 'Edm.String',\n searchable: true,\n filterable: false,\n sortable: false,\n facetable: false,\n },\n ];\n\n // Merge default fields with additional fields (avoid duplicates)\n const existingFieldNames = new Set(defaultFields.map(f => f.name));\n const metadataIndexFields = this.getMetadataIndexFields(metadataIndexes, additionalFields);\n const allFields = [\n ...defaultFields,\n ...metadataIndexFields,\n ...additionalFields.filter(field => !existingFieldNames.has(field.name)),\n ];\n\n // HNSW parameters with customizable values\n const hnswConfig = {\n metric: similarityFunction,\n m: hnswParameters.m ?? 4,\n efConstruction: hnswParameters.efConstruction ?? 400,\n efSearch: hnswParameters.efSearch ?? 500,\n };\n\n const indexDefinition: any = {\n name: indexName,\n fields: allFields,\n vectorSearch: {\n profiles: [\n {\n name: 'vector-profile',\n algorithmConfigurationName: 'vector-algorithm',\n ...(compression && { compressionName: 'vector-compression' }),\n },\n ],\n algorithms: [\n {\n name: 'vector-algorithm',\n kind: 'hnsw',\n hnswParameters: hnswConfig,\n },\n ],\n ...(compression && {\n compressions: [\n {\n kind: compression.kind ?? 'scalarQuantization',\n compressionName: 'vector-compression',\n // Rescoring with full-precision vectors is what makes `oversampling`\n // meaningful: oversampling widens the initial (compressed) candidate\n // set so the rescore step has more to recover recall from.\n rescoringOptions: {\n enableRescoring: true,\n defaultOversampling: 10,\n },\n },\n ],\n }),\n },\n };\n\n // Add semantic search configuration if provided.\n // Note: the SDK's SearchIndex field is `semanticSearch`, not `semantic`, and its\n // SemanticField entries use `name`, not `fieldName` — an unrecognized top-level\n // property is silently dropped by the service rather than rejected, so a wrong\n // shape here does not surface as a createIndex error, only later as \"this index\n // must have valid semantic configurations defined\" from a semantic query.\n if (semanticConfig) {\n const prioritizedFields = semanticConfig.prioritizedFields ?? {\n titleField: { fieldName: 'content' },\n prioritizedContentFields: [{ fieldName: 'content' }],\n };\n indexDefinition.semanticSearch = {\n configurations: [\n {\n name: semanticConfig.name ?? 'default-semantic-config',\n prioritizedFields: {\n ...(prioritizedFields.titleField && {\n titleField: { name: prioritizedFields.titleField.fieldName },\n }),\n ...(prioritizedFields.prioritizedContentFields && {\n contentFields: prioritizedFields.prioritizedContentFields.map(f => ({ name: f.fieldName })),\n }),\n ...(prioritizedFields.prioritizedKeywordsFields && {\n keywordsFields: prioritizedFields.prioritizedKeywordsFields.map(f => ({ name: f.fieldName })),\n }),\n },\n },\n ],\n };\n }\n\n await this.indexClient.createIndex(indexDefinition as any);\n\n // Index created successfully\n } catch (error: any) {\n // Check if index already exists\n if (error?.statusCode === 409 || error?.message?.includes('already exists')) {\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...this.getMetadataIndexFields(metadataIndexes, additionalFields), ...additionalFields],\n });\n // Index already exists, that's fine\n return;\n }\n\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, dimension, metric },\n },\n error,\n );\n }\n }\n\n /**\n * Creates an advanced vector search index with full Azure AI Search capabilities\n *\n * @param params - Extended Azure AI Search index creation parameters\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createAdvancedIndex(params: AzureAISearchCreateIndexParams): Promise<void> {\n return this.createIndex(params);\n }\n\n /**\n * Lists all available indexes in the Azure AI Search service\n *\n * @returns Array of index names\n * @throws {MastraError} When listing indexes fails\n */\n async listIndexes(): Promise<string[]> {\n try {\n const indexes = [];\n const indexIterator = this.indexClient.listIndexes();\n\n for await (const index of indexIterator) {\n indexes.push(index.name);\n }\n\n return indexes;\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_LIST_INDEXES_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n },\n error,\n );\n }\n }\n\n /**\n * Retrieves statistics and configuration information about an index\n *\n * @param indexName - Name of the index to describe\n * @returns Index statistics including dimension, count, and metric\n * @throws {MastraError} When describing index fails\n */\n async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {\n try {\n // Get index definition\n const index = await this.indexClient.getIndex(indexName);\n\n // Get document count\n const searchClient = this.getSearchClient(indexName);\n const countResult = await searchClient.getDocumentsCount();\n\n const { dimension } = this.schemaFromIndex(index);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n\n // Extract metric from vector search configuration\n let metric: 'cosine' | 'euclidean' | 'dotproduct' = 'cosine';\n if (index.vectorSearch?.algorithms) {\n const algorithm = index.vectorSearch.algorithms[0] as any;\n if (algorithm?.hnswParameters?.metric) {\n const azureMetric = algorithm.hnswParameters.metric;\n // Reverse lookup\n const metricEntry = Object.entries(METRIC_MAPPING).find(([_, value]) => value === azureMetric);\n if (metricEntry) {\n metric = metricEntry[0] as 'cosine' | 'euclidean' | 'dotproduct';\n }\n }\n }\n\n return { dimension, count: countResult, metric };\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DESCRIBE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes an index and all its documents\n *\n * @param indexName - Name of the index to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {\n try {\n await this.indexClient.deleteIndex(indexName);\n\n // Remove cached search client\n this.searchClients.delete(indexName);\n\n // Index deleted successfully\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Inserts or updates vectors in the specified index\n *\n * @param indexName - Name of the index to upsert into\n * @param vectors - Array of vectors to upsert\n * @param metadata - Array of metadata objects corresponding to each vector\n * @param ids - Array of IDs corresponding to each vector (auto-generated if not provided)\n * @returns Array of IDs of the upserted vectors\n * @throws {MastraError} When upsert operation fails\n */\n async upsert({ indexName, vectors, metadata = [], ids, deleteFilter }: AzureAISearchUpsertParams): Promise<string[]> {\n if (!Array.isArray(vectors) || vectors.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_EMPTY_VECTORS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Cannot upsert an empty vectors array',\n details: { indexName },\n });\n }\n if (metadata.length > 0 && metadata.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_METADATA_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and metadata must have the same length. Got ${vectors.length} vectors and ${metadata.length} metadata entries.`,\n details: { indexName, vectorsLength: vectors.length, metadataLength: metadata.length },\n });\n }\n if (ids && ids.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_IDS_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and ids must have the same length. Got ${vectors.length} vectors and ${ids.length} ids.`,\n details: { indexName, vectorsLength: vectors.length, idsLength: ids.length },\n });\n }\n\n try {\n if (deleteFilter) {\n await this.deleteVectors({ indexName, filter: deleteFilter });\n }\n\n // One schema read gives us the vector field, its dimension, and field types.\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions(vectors, dimension);\n await this.ensureMetadataFields({ indexName, metadataList: metadata, vectorFieldName, fields });\n\n // Generate IDs if not provided\n const vectorIds = ids || vectors.map(() => crypto.randomUUID());\n\n // Prepare documents for upload using dynamic vector field\n const documents = vectors.map((vector: number[], i: number) =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(vectorIds[i]!),\n vector,\n vectorFieldName,\n metadata: metadata[i] || {},\n fields,\n }),\n );\n\n // Upload documents (batched to respect Azure's per-request limits)\n const searchClient = this.getSearchClient(indexName);\n const uploadResults = await this.runBatchedIndexing(documents, batch =>\n searchClient.uploadDocuments(batch as any),\n );\n\n // Check for failures\n const failures = uploadResults.filter(result => !result.succeeded);\n if (failures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: uploadResults.length,\n failedCount: failures.length,\n firstFailedKey: failures[0]?.key || 'unknown',\n firstFailedError: failures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${failures.length} of ${uploadResults.length} documents failed to upload`),\n );\n }\n\n return vectorIds;\n } catch (error) {\n // If it's already a MastraError (e.g., from partial failure above), re-throw it\n if (error instanceof MastraError) {\n throw error;\n }\n\n // Normalize error to Error instance to avoid unsafe casting\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n\n // Otherwise, wrap the error in a MastraError\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, vectorCount: vectors?.length || 0 },\n },\n normalizedError,\n );\n }\n }\n\n /**\n * Standard MastraVector query method - compatible with Memory integration\n *\n * @param params - Standard query parameters compatible with MastraVector interface\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async query(params: QueryVectorParams<AzureAISearchVectorFilter>): Promise<QueryResult[]> {\n return this.advancedQuery(params);\n }\n\n /**\n * Advanced vector similarity search with full Azure AI Search capabilities\n *\n * @param indexName - Name of the index to search\n * @param queryVector - Vector to search with\n * @param topK - Maximum number of results to return\n * @param filter - Optional filter to apply to the search\n * @param includeVector - Whether to include the vector in each result (requires an extra retrievable select)\n * @param useSemanticSearch - Enable semantic search for better relevance\n * @param semanticOptions - Configuration for semantic search features\n * @param exhaustiveSearch - Use exhaustive k-NN search for exact results\n * @param oversampling - Oversampling factor for compressed vectors\n * @param weight - Relative weight for this vector query in hybrid scenarios\n * @param queryType - Query type: simple, full, or semantic\n * @param textVectorization - Enable automatic text vectorization\n * @param additionalVectorQueries - Multiple vector queries for hybrid search\n * @param filterMode - Apply filters before or after vector search\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async advancedQuery({\n indexName,\n queryVector,\n filter,\n topK = 10,\n includeVector = false, // Kept for API compatibility but ignored due to Azure AI Search limitations\n useSemanticSearch = false,\n semanticOptions,\n exhaustiveSearch = false,\n oversampling,\n weight = 1.0,\n queryType = 'simple',\n textVectorization,\n additionalVectorQueries = [],\n filterMode = 'preFilter',\n }: AzureAISearchAdvancedQueryParams): Promise<QueryResult[]> {\n try {\n const searchClient = this.getSearchClient(indexName);\n\n // Detect vector field name\n const vectorFieldName = await this.getVectorFieldName(indexName);\n\n // Translate filter to OData syntax\n const odataFilter = this.transformFilter(filter);\n\n // Prepare primary vector query using dynamic field name\n const primaryVectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: queryVector as number[],\n kNearestNeighborsCount: topK,\n fields: [vectorFieldName],\n exhaustive: exhaustiveSearch,\n weight: weight,\n // Oversampling only makes sense for approximate (compressed) search — Azure\n // rejects the combination of oversampling and exhaustive search outright.\n ...(oversampling && !exhaustiveSearch && { oversampling }),\n };\n\n // Prepare additional vector queries for hybrid search\n const allVectorQueries: VectorQuery<any>[] = [primaryVectorQuery];\n\n // Add additional vector queries\n additionalVectorQueries.forEach(vq => {\n const vectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: vq.vector,\n kNearestNeighborsCount: vq.kNearestNeighborsCount || topK,\n fields: vq.fields || [vectorFieldName],\n weight: vq.weight || 1.0,\n exhaustive: exhaustiveSearch,\n };\n allVectorQueries.push(vectorQuery);\n });\n\n // Prepare vector search options\n const vectorSearchOptions: VectorSearchOptions<any> = {\n queries: allVectorQueries,\n filterMode: filterMode,\n };\n\n // Prepare field selection. The vector field is declared `retrievable: true`\n // in the index schema, so it can be selected back when explicitly requested.\n const selectFields = includeVector\n ? ['id', 'metadata', 'content', vectorFieldName]\n : ['id', 'metadata', 'content'];\n\n // Build search options\n let searchOptions: SearchRequestOptions<any> = {\n vectorSearchOptions,\n filter: odataFilter,\n top: topK,\n select: selectFields,\n // Combining a full-text `search` term with vectorSearchOptions makes Azure AI\n // Search run true hybrid search (BM25 + vector, fused via Reciprocal Rank Fusion)\n // in a single request. This needs no server-side vectorizer, unlike a\n // VectorizableTextQuery, which requires one to be configured on the index.\n ...(textVectorization?.fields && { searchFields: textVectorization.fields }),\n };\n\n // Add semantic search if enabled\n if (useSemanticSearch || queryType === 'semantic') {\n const semanticSearchOptions: SemanticSearchOptions = {\n configurationName: semanticOptions?.configurationName || 'default-semantic-config',\n ...(semanticOptions?.semanticQuery && { semanticQuery: semanticOptions.semanticQuery }),\n ...(semanticOptions?.answers && {\n answers: {\n answerType: 'extractive' as const,\n count: 3,\n threshold: 0.7,\n },\n }),\n ...(semanticOptions?.captions && {\n captions: {\n captionType: 'extractive' as const,\n highlight: true,\n },\n }),\n ...(semanticOptions?.maxWaitTime && { maxWaitInMilliseconds: semanticOptions.maxWaitTime }),\n };\n\n searchOptions = {\n ...searchOptions,\n queryType: 'semantic' as const,\n semanticSearchOptions,\n };\n } else {\n searchOptions = {\n ...searchOptions,\n queryType: queryType === 'full' ? ('full' as const) : ('simple' as const),\n };\n }\n\n // Perform search. A text query (from textVectorization.text) is passed as the\n // full-text search term rather than vectorized server-side, so hybrid search\n // works against any index without requiring a configured vectorizer.\n const searchResults = await searchClient.search(textVectorization?.text ?? '*', searchOptions as any);\n\n // Process results - Azure SDK returns object with .results property\n const results: QueryResult[] = [];\n for await (const result of searchResults.results) {\n if (result.document) {\n const queryResult: QueryResult = {\n id: decodeDocumentKey(result.document.id),\n score: result.score || 0,\n metadata: result.document.metadata\n ? (() => {\n try {\n return JSON.parse(result.document.metadata);\n } catch {\n return { _raw: result.document.metadata };\n }\n })()\n : {},\n document: result.document.content,\n ...(includeVector && { vector: (result.document as Record<string, any>)[vectorFieldName] }),\n };\n\n // Add semantic-specific fields if available\n if (result.rerankerScore) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.rerankerScore'] = result.rerankerScore;\n }\n if (result.captions && result.captions.length > 0) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.captions'] = result.captions;\n }\n if (result.highlights) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.highlights'] = result.highlights;\n }\n\n results.push(queryResult);\n }\n }\n\n return results;\n } catch (error) {\n const unknownField = this.unknownFilterField(error);\n if (unknownField) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_FILTER_UNKNOWN_FIELD',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Filter references metadata field '${unknownField}' which does not exist on index '${indexName}'. Azure AI Search can only filter on declared fields: either upsert at least one document carrying '${unknownField}' as a string/number/boolean value (autoIndexMetadata), or declare it via createIndex({ metadataIndexes: ['${unknownField}'] }).`,\n details: { indexName, field: unknownField },\n },\n error,\n );\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_QUERY_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, topK },\n },\n error,\n );\n }\n }\n\n /**\n * Updates a vector and/or its metadata by ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to update\n * @param update - Object containing vector and/or metadata updates\n * @throws {MastraError} When update operation fails\n */\n async updateVector({ indexName, id, filter, update }: AzureAISearchUpdateParams): Promise<void> {\n try {\n if (!update.vector && !update.metadata) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_NO_UPDATES',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'No updates provided',\n });\n }\n\n if (!id && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_ID_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either id or filter must be provided',\n });\n }\n\n if (id && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_ID_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot provide both id and filter - they are mutually exclusive',\n });\n }\n\n const searchClient = this.getSearchClient(indexName);\n\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n\n // Validate vector dimension if updating vector\n if (update.vector) {\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions([update.vector], dimension);\n }\n\n let targetIds: string[];\n if (id) {\n targetIds = [id];\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot update with empty filter',\n });\n }\n targetIds = await this.findIdsByFilter(indexName, filter);\n }\n\n if (targetIds.length === 0) {\n return;\n }\n\n if (update.metadata) {\n await this.ensureMetadataFields({ indexName, metadataList: [update.metadata], vectorFieldName, fields });\n }\n\n const updatedDocs = targetIds.map(targetId =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(targetId),\n vector: update.vector,\n vectorFieldName,\n metadata: update.metadata,\n fields,\n writeMetadata: Boolean(update.metadata),\n }),\n );\n\n // Merge documents (update operation, batched to respect Azure's per-request limits)\n const mergeResults = await this.runBatchedIndexing(updatedDocs, batch =>\n searchClient.mergeDocuments(batch as any),\n );\n\n // Check for per-document failures\n const mergeFailures = mergeResults.filter(result => !result.succeeded);\n if (mergeFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: mergeResults.length,\n failedCount: mergeFailures.length,\n firstFailedKey: mergeFailures[0]?.key || 'unknown',\n firstFailedError: mergeFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${mergeFailures.length} of ${mergeResults.length} documents failed to update`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, ...(id ? { id } : {}) },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes multiple vectors by IDs or metadata filter.\n */\n async deleteVectors({ indexName, ids, filter }: AzureAISearchDeleteVectorsParams): Promise<void> {\n try {\n if (ids && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_IDS_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot specify both ids and filter - they are mutually exclusive',\n });\n }\n\n if (!ids && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_IDS_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either filter or ids must be provided',\n });\n }\n\n let idsToDelete: string[];\n if (ids) {\n if (ids.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_IDS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty ids array',\n });\n }\n idsToDelete = ids;\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty filter',\n });\n }\n idsToDelete = await this.findIdsByFilter(indexName, filter);\n }\n\n if (idsToDelete.length === 0) {\n return;\n }\n\n const searchClient = this.getSearchClient(indexName);\n const deleteDocs = idsToDelete.map(id => ({ id: encodeDocumentKey(id) }));\n const deleteResults = await this.runBatchedIndexing(deleteDocs, batch =>\n searchClient.deleteDocuments(batch as any),\n );\n\n // Check for per-document failures\n const deleteFailures = deleteResults.filter(result => !result.succeeded);\n if (deleteFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: deleteResults.length,\n failedCount: deleteFailures.length,\n firstFailedKey: deleteFailures[0]?.key || 'unknown',\n firstFailedError: deleteFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${deleteFailures.length} of ${deleteResults.length} documents failed to delete`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTORS_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n idsCount: ids?.length || 0,\n hasFilter: !!filter,\n },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes a vector by its ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {\n try {\n const searchClient = this.getSearchClient(indexName);\n const deleteResult = await searchClient.deleteDocuments([{ id: encodeDocumentKey(id) }] as any);\n const deleteFailure = deleteResult.results.find(result => !result.succeeded);\n\n if (deleteFailure) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n id,\n failedKey: deleteFailure.key || 'unknown',\n error: deleteFailure.errorMessage || 'No error message',\n },\n },\n new Error(`Document ${deleteFailure.key || id} failed to delete`),\n );\n }\n } catch (error: unknown) {\n if (error instanceof MastraError) {\n throw error;\n }\n // Don't throw error if document doesn't exist (404)\n if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 404) {\n return;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, id },\n },\n error,\n );\n }\n }\n\n /**\n * Validates that all vectors have the correct dimension\n */\n private validateVectorDimensions(vectors: number[][], dimension: number): void {\n for (let i = 0; i < vectors.length; i++) {\n if (vectors[i]?.length !== dimension) {\n throw new Error(\n `Vector at index ${i} has invalid dimension ${vectors[i]?.length}. Expected ${dimension} dimensions.`,\n );\n }\n }\n }\n\n /**\n * Extracts the field name from Azure's \"Could not find a property named 'x'\" $filter error.\n */\n private unknownFilterField(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error);\n return /Could not find a property named '([^']+)'/.exec(message)?.[1];\n }\n\n /**\n * Transforms filter to Azure AI Search OData syntax\n */\n private transformFilter(filter?: AzureAISearchVectorFilter): string | undefined {\n const translator = new AzureAISearchFilterTranslator();\n return translator.translate(filter);\n }\n\n /**\n * Finds document IDs matching a filter.\n */\n private async findIdsByFilter(indexName: string, filter: AzureAISearchVectorFilter): Promise<string[]> {\n const searchClient = this.getSearchClient(indexName);\n const odataFilter = this.transformFilter(filter);\n // Only update/delete call this. A filter that is non-empty as an object but\n // translates to no predicate (`{ $and: [] }`, `{ x: { $nin: [] } }`) would\n // otherwise select every document, which is never what a caller meant.\n if (!odataFilter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Filter does not constrain any documents; refusing to apply it to every document',\n });\n }\n\n const ids: string[] = [];\n const pageSize = 1000;\n // Azure AI Search caps $skip at 100,000, so paginate with a stable\n // ordered range scan (\"search after\") on the sortable key field instead.\n let lastId: string | undefined;\n\n while (true) {\n const rangeClause = lastId !== undefined ? `id gt '${lastId.replace(/'/g, \"''\")}'` : undefined;\n const combinedFilter = [odataFilter ? `(${odataFilter})` : undefined, rangeClause].filter(Boolean).join(' and ');\n\n const searchResults = await searchClient.search('*', {\n filter: combinedFilter || undefined,\n top: pageSize,\n orderBy: ['id asc'],\n select: ['id'],\n } as any);\n\n let count = 0;\n for await (const result of searchResults.results) {\n if (result.document?.id) {\n ids.push(decodeDocumentKey(result.document.id));\n // Range-scan cursor must stay in stored (encoded) key space.\n lastId = result.document.id;\n }\n count++;\n }\n\n if (count < pageSize) {\n break;\n }\n }\n\n return ids;\n }\n\n /**\n * Convenience method for semantic search\n *\n * @param params - Query parameters with semantic search enabled\n * @returns Array of search results with semantic enhancements\n */\n async semanticQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'useSemanticSearch' | 'queryType' | 'semanticOptions'> & {\n semanticConfig?: string;\n semanticQuery?: string;\n enableAnswers?: boolean;\n enableCaptions?: boolean;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n useSemanticSearch: true,\n queryType: 'semantic',\n semanticOptions: {\n configurationName: params.semanticConfig,\n semanticQuery: params.semanticQuery,\n answers: params.enableAnswers,\n captions: params.enableCaptions,\n },\n });\n }\n\n /**\n * Convenience method for hybrid vector + text search. Combines the vector query with a\n * BM25 full-text query over `textQuery`, fused via Azure AI Search's native Reciprocal\n * Rank Fusion. No vectorizer needs to be configured on the index.\n *\n * @param params - Query parameters with a text query\n * @returns Array of search results from hybrid search\n */\n async hybridQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'textVectorization'> & {\n textQuery: string;\n /** Searchable text fields to match `textQuery` against. Defaults to the index's default searchable fields. */\n vectorFields?: string[];\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n textVectorization: {\n text: params.textQuery,\n fields: params.vectorFields,\n },\n });\n }\n\n /**\n * Convenience method for multi-vector search\n *\n * @param params - Query parameters with multiple vectors\n * @returns Array of search results from multi-vector search\n */\n async multiVectorQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'additionalVectorQueries'> & {\n vectors: Array<{\n vector: number[];\n weight?: number;\n fields?: string[];\n }>;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n additionalVectorQueries: params.vectors.map(v => ({\n vector: v.vector,\n weight: v.weight,\n fields: v.fields,\n kNearestNeighborsCount: params.topK,\n })),\n });\n }\n\n /**\n * Convenience method for exhaustive (exact) search\n *\n * @param params - Query parameters with exhaustive search enabled\n * @returns Array of search results from exhaustive search\n */\n async exactQuery(params: Omit<AzureAISearchAdvancedQueryParams, 'exhaustiveSearch'>): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n exhaustiveSearch: true,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["MastraVector","SearchIndexClient","AzureKeyCredential","SearchClient","MastraError","ErrorDomain","ErrorCategory"],"sources":["../src/vector/filter.ts","../src/vector/index.ts"],"sourcesContent":["import type { VectorFilter } from '@mastra/core/vector/filter';\n\n/**\n * Metadata filter accepted by `@mastra/azure-ai-search`.\n *\n * This is the standard Mastra filter shape (`$eq`, `$ne`, `$gt`, `$gte`,\n * `$lt`, `$lte`, `$in`, `$nin`, `$exists`, `$and`, `$or`, `$not`), which the\n * translator turns into an Azure AI Search OData `$filter` expression. Raw\n * OData is intentionally not accepted: the same filter selects documents for\n * `updateVector` and `deleteVectors`, so every predicate is built from\n * validated field names and escaped literals.\n */\nexport type AzureAISearchVectorFilter = VectorFilter;\n\n/**\n * An OData predicate that no document can satisfy. Used wherever a filter is\n * syntactically valid but has nothing it could match (`$or: []`, `$in: []`,\n * `field: []`). Returning `undefined` there would drop the filter entirely and\n * match every document, which is the wrong direction for a delete or update.\n * OData requires one side of a comparison to be a field, so this compares the\n * always-present key field against itself.\n */\nconst MATCH_NONE = \"(id eq '__mastra_none__' and id ne '__mastra_none__')\";\n\n/**\n * Translates Mastra vector filters to Azure AI Search OData filter syntax\n */\nexport class AzureAISearchFilterTranslator {\n /**\n * Translates a filter object to OData filter string\n * @param filter - The filter to translate\n * @returns OData filter string or undefined if no filter\n */\n translate(filter?: AzureAISearchVectorFilter): string | undefined {\n if (!filter) {\n return undefined;\n }\n\n const translated = this.translateMastraFilter(filter as Record<string, any>).trim();\n return translated.length > 0 ? translated : undefined;\n }\n\n private translateMastraFilter(filter: Record<string, any>): string {\n const conditions: string[] = [];\n\n for (const [key, value] of Object.entries(filter)) {\n if (key === '$and' && Array.isArray(value)) {\n // An empty $and is vacuously true, so it contributes no clause.\n const andConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n if (andConditions.length > 0) {\n conditions.push(`(${andConditions.join(' and ')})`);\n }\n continue;\n }\n\n if (key === '$or' && Array.isArray(value)) {\n const orConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n conditions.push(orConditions.length > 0 ? `(${orConditions.join(' or ')})` : MATCH_NONE);\n continue;\n }\n\n if (key === '$not' && typeof value === 'object' && value !== null) {\n const notCondition = this.translateMastraFilter(value);\n if (notCondition) {\n conditions.push(`not (${notCondition})`);\n }\n continue;\n }\n\n if (key.startsWith('$')) {\n throw new Error(`Unsupported filter operator '${key}'. Azure AI Search supports $and, $or, and $not.`);\n }\n\n conditions.push(...this.translateMastraFieldCondition(key, value));\n }\n\n return conditions.join(' and ');\n }\n\n private translateMastraFieldCondition(field: string, value: any): string[] {\n if (Array.isArray(value)) {\n return [this.formatInClause(field, value)];\n }\n\n if (value === null || value === undefined || typeof value !== 'object' || value instanceof Date) {\n return [`${this.escapeFieldName(field)} eq ${this.formatValue(value)}`];\n }\n\n const conditions: string[] = [];\n for (const [operator, operatorValue] of Object.entries(value)) {\n switch (operator) {\n case '$eq':\n conditions.push(`${this.escapeFieldName(field)} eq ${this.formatValue(operatorValue)}`);\n break;\n case '$ne':\n conditions.push(`${this.escapeFieldName(field)} ne ${this.formatValue(operatorValue)}`);\n break;\n case '$gt':\n conditions.push(`${this.escapeFieldName(field)} gt ${this.formatValue(operatorValue)}`);\n break;\n case '$gte':\n conditions.push(`${this.escapeFieldName(field)} ge ${this.formatValue(operatorValue)}`);\n break;\n case '$lt':\n conditions.push(`${this.escapeFieldName(field)} lt ${this.formatValue(operatorValue)}`);\n break;\n case '$lte':\n conditions.push(`${this.escapeFieldName(field)} le ${this.formatValue(operatorValue)}`);\n break;\n case '$in':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$in on field '${field}' requires an array`);\n }\n conditions.push(this.formatInClause(field, operatorValue));\n break;\n case '$nin':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$nin on field '${field}' requires an array`);\n }\n // \"not in nothing\" is true for every document, so it adds no clause.\n if (operatorValue.length > 0) {\n conditions.push(`not ${this.formatInClause(field, operatorValue)}`);\n }\n break;\n case '$exists':\n conditions.push(`${this.escapeFieldName(field)} ${operatorValue ? 'ne' : 'eq'} null`);\n break;\n case '$not': {\n const negatedConditions = this.translateMastraFieldCondition(field, operatorValue);\n if (negatedConditions.length > 0) {\n conditions.push(`not (${negatedConditions.join(' and ')})`);\n }\n break;\n }\n default:\n throw new Error(\n `Unsupported filter operator '${operator}' on field '${field}'. Azure AI Search supports $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $not.`,\n );\n }\n }\n return conditions;\n }\n\n /**\n * Builds a membership check as an OR-chain of equality comparisons.\n * OData's `in` keyword is not a real operator in Azure AI Search's filter\n * syntax (it only exists as the `search.in()` function, which needs its own\n * comma-escaping for values that may contain the separator), so membership\n * is expressed the portable way: `(field eq v1 or field eq v2 or ...)`.\n * An empty set can match nothing.\n */\n private formatInClause(field: string, values: any[]): string {\n const escapedField = this.escapeFieldName(field);\n if (values.length === 0) {\n return MATCH_NONE;\n }\n return `(${values.map(v => `${escapedField} eq ${this.formatValue(v)}`).join(' or ')})`;\n }\n\n private formatValue(value: any): string {\n if (typeof value === 'string') {\n // Escape single quotes in strings\n const escapedValue = value.replace(/'/g, \"''\");\n return `'${escapedValue}'`;\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'boolean') {\n return value.toString();\n }\n\n if (value === null || value === undefined) {\n return 'null';\n }\n\n return String(value);\n }\n\n private escapeFieldName(field: string): string {\n // Azure AI Search OData uses unquoted field paths (e.g., Address/City)\n // Validate field names to prevent OData injection\n if (!/^[a-zA-Z_][\\w/]*$/.test(field)) {\n throw new Error(`Invalid field name for OData filter: '${field}'`);\n }\n return field;\n }\n}\n","import type { TokenCredential } from '@azure/core-auth';\nimport type {\n VectorQuery,\n VectorSearchOptions,\n SemanticSearchOptions,\n SearchRequestOptions,\n VectorizedQuery,\n SearchClientOptions,\n} from '@azure/search-documents';\nimport { SearchClient, SearchIndexClient, AzureKeyCredential } from '@azure/search-documents';\nimport { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';\nimport type {\n CreateIndexParams,\n DeleteIndexParams,\n DeleteVectorParams,\n DescribeIndexParams,\n IndexStats,\n QueryResult,\n QueryVectorParams,\n UpdateVectorParams,\n UpsertVectorParams,\n} from '@mastra/core/vector';\nimport { MastraVector } from '@mastra/core/vector';\nimport type { AzureAISearchVectorFilter } from './filter';\nimport { AzureAISearchFilterTranslator } from './filter';\n\n/**\n * Configuration options for Azure AI Search vector store\n */\nexport interface AzureAISearchVectorOptions {\n /** The endpoint URL of your Azure AI Search service */\n endpoint: string;\n /** Authentication credential - either API key or Azure credential */\n credential: string | AzureKeyCredential | TokenCredential;\n /** API version (optional, defaults to latest) */\n apiVersion?: string;\n /**\n * Additional options for SearchClient (optional)\n * Use this to pass custom policies like AXET proxy, retry options, etc.\n *\n * @example\n * ```typescript\n * clientOptions: {\n * additionalPolicies: [{\n * position: 'perCall',\n * policy: createAxetProxyPolicy({ ... })\n * }]\n * }\n * ```\n */\n clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n /**\n * Automatically add a filterable field to the index the first time a top-level\n * string/number/boolean metadata key is seen in `upsert`/`updateVector`.\n *\n * Azure AI Search can only filter on fields declared in the index schema and has\n * no JSON-path filtering, so without this, `query({ filter: { thread_id } })` on a\n * key that was never declared via `metadataIndexes` fails with HTTP 400. Mastra\n * Memory relies on filtering by `thread_id`/`resource_id` without declaring them.\n *\n * Field type is inferred from the first value seen. Keys whose names are not valid\n * Azure field names (must match `^[A-Za-z][A-Za-z0-9_]*$`), or whose values are\n * arrays/objects/null, stay in the JSON `metadata` blob only and are not filterable.\n *\n * Defaults to `true`. Set to `false` to require explicit `metadataIndexes`.\n */\n autoIndexMetadata?: boolean;\n}\n\n/**\n * Azure AI Search document keys may only contain letters, digits, `_`, `-` and `=`.\n * IDs that use anything else (e.g. `urn:uuid:...`, paths, emails) are base64url\n * encoded behind a marker prefix and decoded back on every read path.\n */\nconst SAFE_DOCUMENT_KEY = /^[A-Za-z0-9_\\-=]+$/;\nconst ENCODED_KEY_PREFIX = 'b64-';\n\nfunction encodeDocumentKey(id: string): string {\n if (SAFE_DOCUMENT_KEY.test(id) && !id.startsWith(ENCODED_KEY_PREFIX)) {\n return id;\n }\n return ENCODED_KEY_PREFIX + Buffer.from(id, 'utf8').toString('base64url');\n}\n\nfunction decodeDocumentKey(key: string): string {\n if (!key.startsWith(ENCODED_KEY_PREFIX)) {\n return key;\n }\n return Buffer.from(key.slice(ENCODED_KEY_PREFIX.length), 'base64url').toString('utf8');\n}\n\n/** Azure AI Search field naming rules (letters/digits/underscore, must start with a letter, max 128 chars). */\nconst AZURE_FIELD_NAME = /^[A-Za-z][A-Za-z0-9_]{0,127}$/;\n\nfunction edmTypeForValue(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return 'Edm.String';\n case 'number':\n return Number.isFinite(value) ? 'Edm.Double' : undefined;\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return undefined;\n }\n}\n\nfunction valueMatchesEdmType(value: unknown, edmType: string | undefined): boolean {\n switch (edmType) {\n case 'Edm.String':\n return typeof value === 'string';\n case 'Edm.Double':\n case 'Edm.Int32':\n case 'Edm.Int64':\n return typeof value === 'number' && Number.isFinite(value);\n case 'Edm.Boolean':\n return typeof value === 'boolean';\n default:\n return false;\n }\n}\n\n/**\n * Azure AI Search document structure for vector storage\n */\ninterface AzureAISearchDocument {\n /** Unique identifier for the document */\n id: string;\n /** Vector embedding */\n vector: number[];\n /** Metadata associated with the document (stored as JSON string) */\n metadata: string;\n /** Optional content field */\n content?: string;\n}\n\n/**\n * Mapping of Mastra metrics to Azure AI Search vector similarity functions\n */\nconst METRIC_MAPPING = {\n cosine: 'cosine',\n euclidean: 'euclidean',\n dotproduct: 'dotProduct',\n} as const;\n\nexport type AzureAISearchQueryVectorParams = QueryVectorParams<AzureAISearchVectorFilter>;\n\ntype AzureAISearchUpsertParams = UpsertVectorParams & { deleteFilter?: AzureAISearchVectorFilter };\ntype AzureAISearchUpdateParams = UpdateVectorParams & { filter?: AzureAISearchVectorFilter };\ntype AzureAISearchDeleteVectorsParams = {\n indexName: string;\n ids?: string[];\n filter?: AzureAISearchVectorFilter;\n};\n\ninterface IndexSchema {\n vectorFieldName: string;\n dimension: number | undefined;\n fields: Map<string, IndexFieldCapabilities>;\n}\n\ntype IndexFieldCapabilities = {\n type?: string;\n};\n\nconst DEFAULT_DOCUMENT_FIELDS = new Set(['id', 'metadata', 'content']);\n\n/**\n * Extended index creation parameters for Azure AI Search specific features\n */\nexport interface AzureAISearchCreateIndexParams extends CreateIndexParams {\n /** Name of the vector field (defaults to 'vector') */\n vectorField?: string;\n /** Additional fields to include in the index schema */\n additionalFields?: Array<{\n name: string;\n type: string;\n searchable?: boolean;\n filterable?: boolean;\n retrievable?: boolean;\n sortable?: boolean;\n facetable?: boolean;\n key?: boolean;\n }>;\n /**\n * Metadata keys that should also be created as explicit filterable Azure AI Search fields.\n * A plain string declares a field as `Edm.String` (backward-compatible default). To filter\n * on a numeric or boolean metadata value with the correct Azure field type — required for\n * numeric comparisons like $gt/$gte/$lt/$lte to work, since Azure rejects an unquoted numeric\n * literal against an Edm.String field — pass `{ name, type }` instead.\n */\n metadataIndexes?: Array<string | { name: string; type: 'string' | 'number' | 'boolean' }>;\n /** HNSW algorithm parameters */\n hnswParameters?: {\n m?: number;\n efConstruction?: number;\n efSearch?: number;\n };\n /** Semantic search configuration */\n semanticConfig?: {\n name?: string;\n prioritizedFields?: {\n /** Single title field for semantic ranking */\n titleField?: { fieldName: string };\n /** Content fields for semantic ranking (renamed from contentFields) */\n prioritizedContentFields?: Array<{ fieldName: string }>;\n /** Keywords fields for semantic ranking (renamed from keywordsFields) */\n prioritizedKeywordsFields?: Array<{ fieldName: string }>;\n };\n };\n /**\n * Enable vector compression (quantization) on the index's vector field.\n * Required for the `oversampling` query parameter to have any effect —\n * Azure AI Search only allows oversampling when the vector field has a\n * compression configured, since oversampling compensates for the recall\n * lost to compression.\n */\n compression?: {\n /** Compression kind. Defaults to 'scalarQuantization'. */\n kind?: 'scalarQuantization' | 'binaryQuantization';\n };\n}\n\n/**\n * Extended query parameters for Azure AI Search advanced features\n */\nexport interface AzureAISearchAdvancedQueryParams extends AzureAISearchQueryVectorParams {\n /** Enable semantic search capabilities */\n useSemanticSearch?: boolean;\n /** Semantic search configuration */\n semanticOptions?: {\n /** Name of semantic configuration in the index */\n configurationName?: string;\n /** Separate query for semantic reranking */\n semanticQuery?: string;\n /** Enable answer extraction from documents */\n answers?: boolean;\n /** Enable caption extraction from documents */\n captions?: boolean;\n /** Maximum wait time for semantic processing (ms) */\n maxWaitTime?: number;\n };\n /** Use exhaustive k-NN search for exact results */\n exhaustiveSearch?: boolean;\n /** Oversampling factor for compressed vectors */\n oversampling?: number;\n /** Relative weight for this vector query in hybrid scenarios */\n weight?: number;\n /** Query type: simple, full, or semantic */\n queryType?: 'simple' | 'full' | 'semantic';\n /**\n * Combine a full-text query with the vector query for hybrid search.\n * Runs as native Azure AI Search hybrid search (BM25 full-text + vector,\n * fused via Reciprocal Rank Fusion) — no vectorizer needs to be configured\n * on the index, unlike Azure's server-side query vectorization.\n */\n textVectorization?: {\n /** Text to search for (BM25 full-text search term) */\n text: string;\n /** Searchable text fields to match against. Defaults to the index's default searchable fields (e.g. content). */\n fields?: string[];\n };\n /** Multiple vector queries for hybrid search */\n additionalVectorQueries?: Array<{\n vector: number[];\n fields?: string[];\n weight?: number;\n kNearestNeighborsCount?: number;\n }>;\n /** Vector filter mode: apply before or after vector search */\n filterMode?: 'preFilter' | 'postFilter';\n}\n\n/**\n * Azure AI Search vector store implementation for Mastra\n *\n * This implementation provides vector storage and similarity search capabilities\n * using Azure AI Search's vector search features.\n *\n * @example\n * ```typescript\n * const azureVector = new AzureAISearchVector({\n * id: 'azure-search-vectors',\n * endpoint: 'https://your-service.search.windows.net',\n * credential: 'your-api-key'\n * });\n *\n * // Create an index\n * await azureVector.createIndex({\n * indexName: 'products',\n * dimension: 1536,\n * metric: 'cosine'\n * });\n *\n * // Insert vectors\n * const ids = await azureVector.upsert({\n * indexName: 'products',\n * vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],\n * metadata: [{ category: 'electronics' }, { category: 'books' }]\n * });\n *\n * // Search vectors\n * const results = await azureVector.query({\n * indexName: 'products',\n * queryVector: [0.1, 0.2, ...],\n * topK: 5,\n * filter: { eq: { category: 'electronics' } }\n * });\n * ```\n */\nexport class AzureAISearchVector extends MastraVector<AzureAISearchVectorFilter> {\n private endpoint: string;\n private credential: string | AzureKeyCredential | TokenCredential;\n private apiVersion?: string;\n private clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n private indexClient: SearchIndexClient;\n private searchClients: Map<string, SearchClient<AzureAISearchDocument>> = new Map();\n private autoIndexMetadata: boolean;\n /**\n * Serializes schema updates per index within this process. `createOrUpdateIndex`\n * is last-writer-wins, so two concurrent upserts each adding a different new\n * metadata field would otherwise clobber each other's field.\n */\n private schemaUpdateQueues: Map<string, Promise<void>> = new Map();\n\n /**\n * Azure AI Search rejects indexing requests containing more than 1,000 documents\n * (and any request larger than 16 MB). Chunk large upload/merge/delete calls to\n * stay within these per-request limits.\n */\n private static readonly INDEXING_BATCH_SIZE = 1000;\n\n constructor({\n id,\n endpoint,\n credential,\n apiVersion,\n clientOptions,\n autoIndexMetadata = true,\n }: AzureAISearchVectorOptions & { id: string }) {\n super({ id });\n\n this.endpoint = endpoint;\n this.credential = credential;\n this.apiVersion = apiVersion;\n this.clientOptions = clientOptions;\n this.autoIndexMetadata = autoIndexMetadata;\n\n // Initialize the index client for managing indexes\n this.indexClient = new SearchIndexClient(\n endpoint,\n typeof credential === 'string' ? new AzureKeyCredential(credential) : credential,\n {\n apiVersion,\n ...clientOptions, // Apply client options to index client as well\n },\n );\n }\n\n /**\n * Static factory method for easier instantiation with connection string\n */\n static fromConnectionString(connectionString: string, options?: { id?: string; apiVersion?: string }) {\n const url = new URL(connectionString);\n const endpoint = url.origin;\n const apiKey = url.searchParams.get('api-key') || url.searchParams.get('key');\n\n if (!apiKey) {\n throw new Error('API key not found in connection string');\n }\n\n return new AzureAISearchVector({\n id: options?.id || 'azure-ai-search',\n endpoint,\n credential: apiKey,\n apiVersion: options?.apiVersion,\n });\n }\n\n /**\n * Gets or creates a search client for a specific index\n */\n private getSearchClient(indexName: string): SearchClient<AzureAISearchDocument> {\n if (!this.searchClients.has(indexName)) {\n const client = new SearchClient<AzureAISearchDocument>(\n this.endpoint,\n indexName,\n typeof this.credential === 'string' ? new AzureKeyCredential(this.credential) : this.credential,\n {\n apiVersion: this.apiVersion,\n ...this.clientOptions, // Merge custom client options\n },\n );\n this.searchClients.set(indexName, client);\n }\n return this.searchClients.get(indexName)!;\n }\n\n /**\n * Runs an indexing operation (upload/merge/delete) in batches that respect\n * Azure AI Search's 1,000-document per-request limit, aggregating the\n * per-document results across all batches.\n */\n private async runBatchedIndexing<R extends { succeeded: boolean; key: string; errorMessage?: string }>(\n documents: unknown[],\n operation: (batch: unknown[]) => Promise<{ results: R[] }>,\n ): Promise<R[]> {\n const results: R[] = [];\n for (let i = 0; i < documents.length; i += AzureAISearchVector.INDEXING_BATCH_SIZE) {\n const batch = documents.slice(i, i + AzureAISearchVector.INDEXING_BATCH_SIZE);\n const { results: batchResults } = await this.retryWhileSchemaPropagates(() => operation(batch));\n results.push(...batchResults);\n }\n return results;\n }\n\n /**\n * A field added with `createOrUpdateIndex` is not immediately visible to the\n * indexing endpoint; an upload issued right after can be rejected with\n * \"The property 'x' does not exist on type 'search.documentFields'\". Retry that\n * specific error briefly while the schema change propagates.\n */\n private async retryWhileSchemaPropagates<T>(operation: () => Promise<T>): Promise<T> {\n const maxAttempts = 20;\n const delayMs = 500;\n for (let attempt = 1; ; attempt++) {\n try {\n return await operation();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const schemaLag = /does not exist on type 'search\\.documentFields'/.test(message);\n if (!schemaLag || attempt >= maxAttempts) {\n throw error;\n }\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n }\n\n /**\n * Reads the index definition once and derives everything a write path needs\n * from it: the vector field name, its dimension, and per-field capabilities.\n * `@azure/search-documents` does not cache `getIndex`, so callers that need\n * more than one of these must share a single read.\n */\n private async readIndexSchema(indexName: string): Promise<IndexSchema> {\n const index = await this.indexClient.getIndex(indexName);\n return this.schemaFromIndex(index);\n }\n\n private schemaFromIndex(index: { fields?: unknown[] }): IndexSchema {\n const fields = new Map<string, IndexFieldCapabilities>();\n let vectorFieldName = 'vector';\n let dimension: number | undefined;\n\n for (const raw of index.fields ?? []) {\n const field = raw as { name: string; type: string; dimensions?: number; vectorSearchDimensions?: number };\n fields.set(field.name, { type: field.type });\n const dims = field.dimensions ?? field.vectorSearchDimensions;\n if (dimension === undefined && field.type === 'Collection(Edm.Single)' && dims) {\n vectorFieldName = field.name;\n dimension = dims;\n }\n }\n\n return { vectorFieldName, dimension, fields };\n }\n\n /**\n * Detects the vector field name in an existing index\n * Falls back to 'vector' for backward compatibility\n */\n private async getVectorFieldName(indexName: string): Promise<string> {\n try {\n return (await this.readIndexSchema(indexName)).vectorFieldName;\n } catch {\n // If we can't determine the vector field name, fall back to 'vector' for backward compatibility\n return 'vector';\n }\n }\n\n private getMetadataIndexFields(\n metadataIndexes: NonNullable<AzureAISearchCreateIndexParams['metadataIndexes']>,\n additionalFields: AzureAISearchCreateIndexParams['additionalFields'],\n ) {\n const edmTypeFor = (type?: 'string' | 'number' | 'boolean'): string => {\n switch (type) {\n case 'number':\n return 'Edm.Double';\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return 'Edm.String';\n }\n };\n\n const reservedFieldNames = new Set(['id', 'metadata', 'content', 'vector']);\n return metadataIndexes\n .map(entry => (typeof entry === 'string' ? { name: entry, type: 'string' as const } : entry))\n .filter(\n entry => !reservedFieldNames.has(entry.name) && !additionalFields?.some(field => field.name === entry.name),\n )\n .map(entry => ({\n name: entry.name,\n type: edmTypeFor(entry.type),\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n }));\n }\n\n private async ensureExistingIndexFields({\n indexName,\n fields,\n }: {\n indexName: string;\n fields: Array<Record<string, any>>;\n }): Promise<void> {\n if (fields.length === 0) {\n return;\n }\n\n const previous = this.schemaUpdateQueues.get(indexName) ?? Promise.resolve();\n const run = previous\n .catch(() => {})\n .then(async () => {\n // Re-read inside the lock so we merge onto whatever the previous update wrote.\n const existingIndex = (await this.indexClient.getIndex(indexName)) as any;\n const existingFieldNames = new Set((existingIndex.fields ?? []).map((field: any) => field.name));\n const missingFields = fields.filter(field => !existingFieldNames.has(field.name));\n\n if (missingFields.length === 0) {\n return;\n }\n\n await (this.indexClient as any).createOrUpdateIndex({\n ...existingIndex,\n fields: [...(existingIndex.fields ?? []), ...missingFields],\n });\n });\n this.schemaUpdateQueues.set(indexName, run);\n try {\n await run;\n } finally {\n if (this.schemaUpdateQueues.get(indexName) === run) {\n this.schemaUpdateQueues.delete(indexName);\n }\n }\n }\n\n /**\n * Adds a filterable field for every top-level scalar metadata key that the index\n * does not yet have, so that `filter: { key: value }` works without the caller\n * declaring the key up front. Mutates `fields` so the subsequent document build\n * writes the typed column. No-op when `autoIndexMetadata` is false.\n */\n private async ensureMetadataFields({\n indexName,\n metadataList,\n vectorFieldName,\n fields,\n }: {\n indexName: string;\n metadataList: Array<Record<string, any> | undefined>;\n vectorFieldName: string;\n fields: Map<string, IndexFieldCapabilities>;\n }): Promise<void> {\n if (!this.autoIndexMetadata) {\n return;\n }\n\n const missing = new Map<string, string>();\n for (const metadata of metadataList) {\n if (!metadata) continue;\n for (const [key, value] of Object.entries(metadata)) {\n if (fields.has(key) || missing.has(key)) continue;\n if (DEFAULT_DOCUMENT_FIELDS.has(key) || key === vectorFieldName) continue;\n // Names starting with \"azureSearch\" are reserved by the service.\n if (!AZURE_FIELD_NAME.test(key) || key.startsWith('azureSearch')) continue;\n const edmType = edmTypeForValue(value);\n if (!edmType) continue;\n missing.set(key, edmType);\n }\n }\n\n if (missing.size === 0) {\n return;\n }\n\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...missing].map(([name, type]) => ({\n name,\n type,\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n })),\n });\n\n // Another writer may have declared the field with a different type; re-read\n // the authoritative schema rather than trusting our inferred types.\n const refreshed = (await this.readIndexSchema(indexName)).fields;\n for (const [name, capability] of refreshed) {\n fields.set(name, capability);\n }\n }\n\n private buildDocumentFromMetadata({\n id,\n vector,\n vectorFieldName,\n metadata = {},\n fields,\n writeMetadata = true,\n }: {\n id: string;\n vector?: number[];\n vectorFieldName: string;\n metadata?: Record<string, any>;\n fields: Map<string, IndexFieldCapabilities>;\n writeMetadata?: boolean;\n }): Record<string, any> {\n const doc: Record<string, any> = { id };\n\n if (writeMetadata) {\n doc.metadata = JSON.stringify(metadata);\n }\n\n if (vector) {\n doc[vectorFieldName] = vector;\n }\n\n // `content` is derived from metadata, so whenever the metadata blob is\n // (re)written the column must follow it; otherwise a merge would keep a\n // stale value from the previous document.\n if (typeof metadata.content === 'string') {\n doc.content = metadata.content;\n } else if (writeMetadata) {\n doc.content = '';\n }\n\n for (const [fieldName, field] of fields.entries()) {\n if (DEFAULT_DOCUMENT_FIELDS.has(fieldName) || fieldName === vectorFieldName) {\n continue;\n }\n\n if (field.type === 'Collection(Edm.Single)') {\n continue;\n }\n\n // Only write the typed column when the JS value matches the column's Edm type.\n // Azure rejects the whole document otherwise (e.g. number into Edm.String:\n // \"Cannot convert the literal '0' to the expected type 'Edm.String'\"). The\n // JSON `metadata` blob remains the source of truth on read either way.\n if (Object.prototype.hasOwnProperty.call(metadata, fieldName)) {\n doc[fieldName] = valueMatchesEdmType(metadata[fieldName], field.type) ? metadata[fieldName] : null;\n }\n }\n\n return doc;\n }\n\n /**\n * Creates a new vector search index with the specified configuration\n *\n * @param params - Index creation parameters (supports both basic Mastra interface and Azure AI Search extended options)\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createIndex(params: CreateIndexParams | AzureAISearchCreateIndexParams): Promise<void> {\n const {\n indexName,\n dimension,\n metric = 'cosine',\n vectorField = 'vector',\n additionalFields = [],\n metadataIndexes = [],\n hnswParameters = {},\n semanticConfig,\n compression,\n } = params as AzureAISearchCreateIndexParams;\n\n if (!Number.isInteger(dimension) || dimension <= 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_INVALID_DIMENSION',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Dimension must be a positive integer',\n details: { indexName, dimension },\n });\n }\n\n try {\n const similarityFunction = METRIC_MAPPING[metric as keyof typeof METRIC_MAPPING];\n\n // Vector field configuration (customizable name).\n // Both `retrievable` and `hidden` are set: some API versions key retrievability\n // off `retrievable`, newer ones off `hidden` (inverted) — the service otherwise\n // silently defaults new vector fields to hidden/non-retrievable and `$select`ing\n // them for `includeVector` fails with \"'vector' is not a retrievable field\".\n const vectorFieldConfig = {\n name: vectorField,\n type: 'Collection(Edm.Single)',\n searchable: true,\n retrievable: true,\n hidden: false,\n vectorSearchDimensions: dimension,\n vectorSearchProfileName: 'vector-profile',\n };\n\n // Core default fields (aligned with other Mastra vector stores)\n const defaultFields = [\n {\n name: 'id',\n type: 'Edm.String',\n key: true,\n filterable: true,\n // Sortable so filter-based lookups can page past Azure's 100,000 $skip\n // ceiling using a stable ordered range scan (see findIdsByFilter).\n sortable: true,\n facetable: false,\n searchable: false,\n },\n vectorFieldConfig,\n {\n name: 'metadata',\n type: 'Edm.String',\n searchable: false,\n filterable: true,\n sortable: false,\n facetable: false,\n },\n {\n name: 'content',\n type: 'Edm.String',\n searchable: true,\n filterable: false,\n sortable: false,\n facetable: false,\n },\n ];\n\n // Merge default fields with additional fields (avoid duplicates)\n const existingFieldNames = new Set(defaultFields.map(f => f.name));\n const metadataIndexFields = this.getMetadataIndexFields(metadataIndexes, additionalFields);\n const allFields = [\n ...defaultFields,\n ...metadataIndexFields,\n ...additionalFields.filter(field => !existingFieldNames.has(field.name)),\n ];\n\n // HNSW parameters with customizable values\n const hnswConfig = {\n metric: similarityFunction,\n m: hnswParameters.m ?? 4,\n efConstruction: hnswParameters.efConstruction ?? 400,\n efSearch: hnswParameters.efSearch ?? 500,\n };\n\n const indexDefinition: any = {\n name: indexName,\n fields: allFields,\n vectorSearch: {\n profiles: [\n {\n name: 'vector-profile',\n algorithmConfigurationName: 'vector-algorithm',\n ...(compression && { compressionName: 'vector-compression' }),\n },\n ],\n algorithms: [\n {\n name: 'vector-algorithm',\n kind: 'hnsw',\n hnswParameters: hnswConfig,\n },\n ],\n ...(compression && {\n compressions: [\n {\n kind: compression.kind ?? 'scalarQuantization',\n compressionName: 'vector-compression',\n // Rescoring with full-precision vectors is what makes `oversampling`\n // meaningful: oversampling widens the initial (compressed) candidate\n // set so the rescore step has more to recover recall from.\n rescoringOptions: {\n enableRescoring: true,\n defaultOversampling: 10,\n },\n },\n ],\n }),\n },\n };\n\n // Add semantic search configuration if provided.\n // Note: the SDK's SearchIndex field is `semanticSearch`, not `semantic`, and its\n // SemanticField entries use `name`, not `fieldName` — an unrecognized top-level\n // property is silently dropped by the service rather than rejected, so a wrong\n // shape here does not surface as a createIndex error, only later as \"this index\n // must have valid semantic configurations defined\" from a semantic query.\n if (semanticConfig) {\n const prioritizedFields = semanticConfig.prioritizedFields ?? {\n titleField: { fieldName: 'content' },\n prioritizedContentFields: [{ fieldName: 'content' }],\n };\n indexDefinition.semanticSearch = {\n configurations: [\n {\n name: semanticConfig.name ?? 'default-semantic-config',\n prioritizedFields: {\n ...(prioritizedFields.titleField && {\n titleField: { name: prioritizedFields.titleField.fieldName },\n }),\n ...(prioritizedFields.prioritizedContentFields && {\n contentFields: prioritizedFields.prioritizedContentFields.map(f => ({ name: f.fieldName })),\n }),\n ...(prioritizedFields.prioritizedKeywordsFields && {\n keywordsFields: prioritizedFields.prioritizedKeywordsFields.map(f => ({ name: f.fieldName })),\n }),\n },\n },\n ],\n };\n }\n\n await this.indexClient.createIndex(indexDefinition as any);\n\n // Index created successfully\n } catch (error: any) {\n // Check if index already exists\n if (error?.statusCode === 409 || error?.message?.includes('already exists')) {\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...this.getMetadataIndexFields(metadataIndexes, additionalFields), ...additionalFields],\n });\n // Index already exists, that's fine\n return;\n }\n\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, dimension, metric },\n },\n error,\n );\n }\n }\n\n /**\n * Creates an advanced vector search index with full Azure AI Search capabilities\n *\n * @param params - Extended Azure AI Search index creation parameters\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createAdvancedIndex(params: AzureAISearchCreateIndexParams): Promise<void> {\n return this.createIndex(params);\n }\n\n /**\n * Lists all available indexes in the Azure AI Search service\n *\n * @returns Array of index names\n * @throws {MastraError} When listing indexes fails\n */\n async listIndexes(): Promise<string[]> {\n try {\n const indexes = [];\n const indexIterator = this.indexClient.listIndexes();\n\n for await (const index of indexIterator) {\n indexes.push(index.name);\n }\n\n return indexes;\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_LIST_INDEXES_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n },\n error,\n );\n }\n }\n\n /**\n * Retrieves statistics and configuration information about an index\n *\n * @param indexName - Name of the index to describe\n * @returns Index statistics including dimension, count, and metric\n * @throws {MastraError} When describing index fails\n */\n async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {\n try {\n // Get index definition\n const index = await this.indexClient.getIndex(indexName);\n\n // Get document count\n const searchClient = this.getSearchClient(indexName);\n const countResult = await searchClient.getDocumentsCount();\n\n const { dimension } = this.schemaFromIndex(index);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n\n // Extract metric from vector search configuration\n let metric: 'cosine' | 'euclidean' | 'dotproduct' = 'cosine';\n if (index.vectorSearch?.algorithms) {\n const algorithm = index.vectorSearch.algorithms[0] as any;\n if (algorithm?.hnswParameters?.metric) {\n const azureMetric = algorithm.hnswParameters.metric;\n // Reverse lookup\n const metricEntry = Object.entries(METRIC_MAPPING).find(([_, value]) => value === azureMetric);\n if (metricEntry) {\n metric = metricEntry[0] as 'cosine' | 'euclidean' | 'dotproduct';\n }\n }\n }\n\n return { dimension, count: countResult, metric };\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DESCRIBE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes an index and all its documents\n *\n * @param indexName - Name of the index to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {\n try {\n await this.indexClient.deleteIndex(indexName);\n\n // Remove cached search client\n this.searchClients.delete(indexName);\n\n // Index deleted successfully\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Inserts or updates vectors in the specified index\n *\n * @param indexName - Name of the index to upsert into\n * @param vectors - Array of vectors to upsert\n * @param metadata - Array of metadata objects corresponding to each vector\n * @param ids - Array of IDs corresponding to each vector (auto-generated if not provided)\n * @returns Array of IDs of the upserted vectors\n * @throws {MastraError} When upsert operation fails\n */\n async upsert({ indexName, vectors, metadata = [], ids, deleteFilter }: AzureAISearchUpsertParams): Promise<string[]> {\n if (!Array.isArray(vectors) || vectors.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_EMPTY_VECTORS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Cannot upsert an empty vectors array',\n details: { indexName },\n });\n }\n if (metadata.length > 0 && metadata.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_METADATA_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and metadata must have the same length. Got ${vectors.length} vectors and ${metadata.length} metadata entries.`,\n details: { indexName, vectorsLength: vectors.length, metadataLength: metadata.length },\n });\n }\n if (ids && ids.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_IDS_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and ids must have the same length. Got ${vectors.length} vectors and ${ids.length} ids.`,\n details: { indexName, vectorsLength: vectors.length, idsLength: ids.length },\n });\n }\n\n try {\n if (deleteFilter) {\n await this.deleteVectors({ indexName, filter: deleteFilter });\n }\n\n // One schema read gives us the vector field, its dimension, and field types.\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions(vectors, dimension);\n await this.ensureMetadataFields({ indexName, metadataList: metadata, vectorFieldName, fields });\n\n // Generate IDs if not provided\n const vectorIds = ids || vectors.map(() => crypto.randomUUID());\n\n // Prepare documents for upload using dynamic vector field\n const documents = vectors.map((vector: number[], i: number) =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(vectorIds[i]!),\n vector,\n vectorFieldName,\n metadata: metadata[i] || {},\n fields,\n }),\n );\n\n // Upload documents (batched to respect Azure's per-request limits)\n const searchClient = this.getSearchClient(indexName);\n const uploadResults = await this.runBatchedIndexing(documents, batch =>\n searchClient.uploadDocuments(batch as any),\n );\n\n // Check for failures\n const failures = uploadResults.filter(result => !result.succeeded);\n if (failures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: uploadResults.length,\n failedCount: failures.length,\n firstFailedKey: failures[0]?.key || 'unknown',\n firstFailedError: failures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${failures.length} of ${uploadResults.length} documents failed to upload`),\n );\n }\n\n return vectorIds;\n } catch (error) {\n // If it's already a MastraError (e.g., from partial failure above), re-throw it\n if (error instanceof MastraError) {\n throw error;\n }\n\n // Normalize error to Error instance to avoid unsafe casting\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n\n // Otherwise, wrap the error in a MastraError\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, vectorCount: vectors?.length || 0 },\n },\n normalizedError,\n );\n }\n }\n\n /**\n * Standard MastraVector query method - compatible with Memory integration\n *\n * @param params - Standard query parameters compatible with MastraVector interface\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async query(params: QueryVectorParams<AzureAISearchVectorFilter>): Promise<QueryResult[]> {\n return this.advancedQuery(params);\n }\n\n /**\n * Advanced vector similarity search with full Azure AI Search capabilities\n *\n * @param indexName - Name of the index to search\n * @param queryVector - Vector to search with\n * @param topK - Maximum number of results to return\n * @param filter - Optional filter to apply to the search\n * @param includeVector - Whether to include the vector in each result (requires an extra retrievable select)\n * @param useSemanticSearch - Enable semantic search for better relevance\n * @param semanticOptions - Configuration for semantic search features\n * @param exhaustiveSearch - Use exhaustive k-NN search for exact results\n * @param oversampling - Oversampling factor for compressed vectors\n * @param weight - Relative weight for this vector query in hybrid scenarios\n * @param queryType - Query type: simple, full, or semantic\n * @param textVectorization - Enable automatic text vectorization\n * @param additionalVectorQueries - Multiple vector queries for hybrid search\n * @param filterMode - Apply filters before or after vector search\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async advancedQuery({\n indexName,\n queryVector,\n filter,\n topK = 10,\n includeVector = false, // Kept for API compatibility but ignored due to Azure AI Search limitations\n useSemanticSearch = false,\n semanticOptions,\n exhaustiveSearch = false,\n oversampling,\n weight = 1.0,\n queryType = 'simple',\n textVectorization,\n additionalVectorQueries = [],\n filterMode = 'preFilter',\n }: AzureAISearchAdvancedQueryParams): Promise<QueryResult[]> {\n try {\n const searchClient = this.getSearchClient(indexName);\n\n // Detect vector field name\n const vectorFieldName = await this.getVectorFieldName(indexName);\n\n // Translate filter to OData syntax\n const odataFilter = this.transformFilter(filter);\n\n // Prepare primary vector query using dynamic field name\n const primaryVectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: queryVector as number[],\n kNearestNeighborsCount: topK,\n fields: [vectorFieldName],\n exhaustive: exhaustiveSearch,\n weight: weight,\n // Oversampling only makes sense for approximate (compressed) search — Azure\n // rejects the combination of oversampling and exhaustive search outright.\n ...(oversampling && !exhaustiveSearch && { oversampling }),\n };\n\n // Prepare additional vector queries for hybrid search\n const allVectorQueries: VectorQuery<any>[] = [primaryVectorQuery];\n\n // Add additional vector queries\n additionalVectorQueries.forEach(vq => {\n const vectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: vq.vector,\n kNearestNeighborsCount: vq.kNearestNeighborsCount || topK,\n fields: vq.fields || [vectorFieldName],\n weight: vq.weight || 1.0,\n exhaustive: exhaustiveSearch,\n };\n allVectorQueries.push(vectorQuery);\n });\n\n // Prepare vector search options\n const vectorSearchOptions: VectorSearchOptions<any> = {\n queries: allVectorQueries,\n filterMode: filterMode,\n };\n\n // Prepare field selection. The vector field is declared `retrievable: true`\n // in the index schema, so it can be selected back when explicitly requested.\n const selectFields = includeVector\n ? ['id', 'metadata', 'content', vectorFieldName]\n : ['id', 'metadata', 'content'];\n\n // Build search options\n let searchOptions: SearchRequestOptions<any> = {\n vectorSearchOptions,\n filter: odataFilter,\n top: topK,\n select: selectFields,\n // Combining a full-text `search` term with vectorSearchOptions makes Azure AI\n // Search run true hybrid search (BM25 + vector, fused via Reciprocal Rank Fusion)\n // in a single request. This needs no server-side vectorizer, unlike a\n // VectorizableTextQuery, which requires one to be configured on the index.\n ...(textVectorization?.fields && { searchFields: textVectorization.fields }),\n };\n\n // Add semantic search if enabled\n if (useSemanticSearch || queryType === 'semantic') {\n const semanticSearchOptions: SemanticSearchOptions = {\n configurationName: semanticOptions?.configurationName || 'default-semantic-config',\n ...(semanticOptions?.semanticQuery && { semanticQuery: semanticOptions.semanticQuery }),\n ...(semanticOptions?.answers && {\n answers: {\n answerType: 'extractive' as const,\n count: 3,\n threshold: 0.7,\n },\n }),\n ...(semanticOptions?.captions && {\n captions: {\n captionType: 'extractive' as const,\n highlight: true,\n },\n }),\n ...(semanticOptions?.maxWaitTime && { maxWaitInMilliseconds: semanticOptions.maxWaitTime }),\n };\n\n searchOptions = {\n ...searchOptions,\n queryType: 'semantic' as const,\n semanticSearchOptions,\n };\n } else {\n searchOptions = {\n ...searchOptions,\n queryType: queryType === 'full' ? ('full' as const) : ('simple' as const),\n };\n }\n\n // Perform search. A text query (from textVectorization.text) is passed as the\n // full-text search term rather than vectorized server-side, so hybrid search\n // works against any index without requiring a configured vectorizer.\n const searchResults = await searchClient.search(textVectorization?.text ?? '*', searchOptions as any);\n\n // Process results - Azure SDK returns object with .results property\n const results: QueryResult[] = [];\n for await (const result of searchResults.results) {\n if (result.document) {\n const queryResult: QueryResult = {\n id: decodeDocumentKey(result.document.id),\n score: result.score || 0,\n metadata: result.document.metadata\n ? (() => {\n try {\n return JSON.parse(result.document.metadata);\n } catch {\n return { _raw: result.document.metadata };\n }\n })()\n : {},\n document: result.document.content,\n ...(includeVector && { vector: (result.document as Record<string, any>)[vectorFieldName] }),\n };\n\n // Add semantic-specific fields if available\n if (result.rerankerScore) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.rerankerScore'] = result.rerankerScore;\n }\n if (result.captions && result.captions.length > 0) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.captions'] = result.captions;\n }\n if (result.highlights) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.highlights'] = result.highlights;\n }\n\n results.push(queryResult);\n }\n }\n\n return results;\n } catch (error) {\n const unknownField = this.unknownFilterField(error);\n if (unknownField) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_FILTER_UNKNOWN_FIELD',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Filter references metadata field '${unknownField}' which does not exist on index '${indexName}'. Azure AI Search can only filter on declared fields: either upsert at least one document carrying '${unknownField}' as a string/number/boolean value (autoIndexMetadata), or declare it via createIndex({ metadataIndexes: ['${unknownField}'] }).`,\n details: { indexName, field: unknownField },\n },\n error,\n );\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_QUERY_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, topK },\n },\n error,\n );\n }\n }\n\n /**\n * Updates a vector and/or its metadata by ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to update\n * @param update - Object containing vector and/or metadata updates\n * @throws {MastraError} When update operation fails\n */\n async updateVector({ indexName, id, filter, update }: AzureAISearchUpdateParams): Promise<void> {\n try {\n if (!update.vector && !update.metadata) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_NO_UPDATES',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'No updates provided',\n });\n }\n\n if (!id && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_ID_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either id or filter must be provided',\n });\n }\n\n if (id && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_ID_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot provide both id and filter - they are mutually exclusive',\n });\n }\n\n const searchClient = this.getSearchClient(indexName);\n\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n\n // Validate vector dimension if updating vector\n if (update.vector) {\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions([update.vector], dimension);\n }\n\n let targetIds: string[];\n if (id) {\n targetIds = [id];\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot update with empty filter',\n });\n }\n targetIds = await this.findIdsByFilter(indexName, filter);\n }\n\n if (targetIds.length === 0) {\n return;\n }\n\n if (update.metadata) {\n await this.ensureMetadataFields({ indexName, metadataList: [update.metadata], vectorFieldName, fields });\n }\n\n const updatedDocs = targetIds.map(targetId =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(targetId),\n vector: update.vector,\n vectorFieldName,\n metadata: update.metadata,\n fields,\n writeMetadata: Boolean(update.metadata),\n }),\n );\n\n // Merge documents (update operation, batched to respect Azure's per-request limits)\n const mergeResults = await this.runBatchedIndexing(updatedDocs, batch =>\n searchClient.mergeDocuments(batch as any),\n );\n\n // Check for per-document failures\n const mergeFailures = mergeResults.filter(result => !result.succeeded);\n if (mergeFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: mergeResults.length,\n failedCount: mergeFailures.length,\n firstFailedKey: mergeFailures[0]?.key || 'unknown',\n firstFailedError: mergeFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${mergeFailures.length} of ${mergeResults.length} documents failed to update`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, ...(id ? { id } : {}) },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes multiple vectors by IDs or metadata filter.\n */\n async deleteVectors({ indexName, ids, filter }: AzureAISearchDeleteVectorsParams): Promise<void> {\n try {\n if (ids && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_IDS_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot specify both ids and filter - they are mutually exclusive',\n });\n }\n\n if (!ids && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_IDS_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either filter or ids must be provided',\n });\n }\n\n let idsToDelete: string[];\n if (ids) {\n if (ids.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_IDS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty ids array',\n });\n }\n idsToDelete = ids;\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty filter',\n });\n }\n idsToDelete = await this.findIdsByFilter(indexName, filter);\n }\n\n if (idsToDelete.length === 0) {\n return;\n }\n\n const searchClient = this.getSearchClient(indexName);\n const deleteDocs = idsToDelete.map(id => ({ id: encodeDocumentKey(id) }));\n const deleteResults = await this.runBatchedIndexing(deleteDocs, batch =>\n searchClient.deleteDocuments(batch as any),\n );\n\n // Check for per-document failures\n const deleteFailures = deleteResults.filter(result => !result.succeeded);\n if (deleteFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: deleteResults.length,\n failedCount: deleteFailures.length,\n firstFailedKey: deleteFailures[0]?.key || 'unknown',\n firstFailedError: deleteFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${deleteFailures.length} of ${deleteResults.length} documents failed to delete`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTORS_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n idsCount: ids?.length || 0,\n hasFilter: !!filter,\n },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes a vector by its ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {\n try {\n const searchClient = this.getSearchClient(indexName);\n const deleteResult = await searchClient.deleteDocuments([{ id: encodeDocumentKey(id) }] as any);\n const deleteFailure = deleteResult.results.find(result => !result.succeeded);\n\n if (deleteFailure) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n id,\n failedKey: deleteFailure.key || 'unknown',\n error: deleteFailure.errorMessage || 'No error message',\n },\n },\n new Error(`Document ${deleteFailure.key || id} failed to delete`),\n );\n }\n } catch (error: unknown) {\n if (error instanceof MastraError) {\n throw error;\n }\n // Don't throw error if document doesn't exist (404)\n if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 404) {\n return;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, id },\n },\n error,\n );\n }\n }\n\n /**\n * Validates that all vectors have the correct dimension\n */\n private validateVectorDimensions(vectors: number[][], dimension: number): void {\n for (let i = 0; i < vectors.length; i++) {\n if (vectors[i]?.length !== dimension) {\n throw new Error(\n `Vector at index ${i} has invalid dimension ${vectors[i]?.length}. Expected ${dimension} dimensions.`,\n );\n }\n }\n }\n\n /**\n * Extracts the field name from Azure's \"Could not find a property named 'x'\" $filter error.\n */\n private unknownFilterField(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error);\n return /Could not find a property named '([^']+)'/.exec(message)?.[1];\n }\n\n /**\n * Transforms filter to Azure AI Search OData syntax\n */\n private transformFilter(filter?: AzureAISearchVectorFilter): string | undefined {\n const translator = new AzureAISearchFilterTranslator();\n return translator.translate(filter);\n }\n\n /**\n * Finds document IDs matching a filter.\n */\n private async findIdsByFilter(indexName: string, filter: AzureAISearchVectorFilter): Promise<string[]> {\n const searchClient = this.getSearchClient(indexName);\n const odataFilter = this.transformFilter(filter);\n // Only update/delete call this. A filter that is non-empty as an object but\n // translates to no predicate (`{ $and: [] }`, `{ x: { $nin: [] } }`) would\n // otherwise select every document, which is never what a caller meant.\n if (!odataFilter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Filter does not constrain any documents; refusing to apply it to every document',\n });\n }\n\n const ids: string[] = [];\n const pageSize = 1000;\n // Azure AI Search caps $skip at 100,000, so paginate with a stable\n // ordered range scan (\"search after\") on the sortable key field instead.\n let lastId: string | undefined;\n\n while (true) {\n const rangeClause = lastId !== undefined ? `id gt '${lastId.replace(/'/g, \"''\")}'` : undefined;\n const combinedFilter = [odataFilter ? `(${odataFilter})` : undefined, rangeClause].filter(Boolean).join(' and ');\n\n const searchResults = await searchClient.search('*', {\n filter: combinedFilter || undefined,\n top: pageSize,\n orderBy: ['id asc'],\n select: ['id'],\n } as any);\n\n let count = 0;\n for await (const result of searchResults.results) {\n if (result.document?.id) {\n ids.push(decodeDocumentKey(result.document.id));\n // Range-scan cursor must stay in stored (encoded) key space.\n lastId = result.document.id;\n }\n count++;\n }\n\n if (count < pageSize) {\n break;\n }\n }\n\n return ids;\n }\n\n /**\n * Convenience method for semantic search\n *\n * @param params - Query parameters with semantic search enabled\n * @returns Array of search results with semantic enhancements\n */\n async semanticQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'useSemanticSearch' | 'queryType' | 'semanticOptions'> & {\n semanticConfig?: string;\n semanticQuery?: string;\n enableAnswers?: boolean;\n enableCaptions?: boolean;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n useSemanticSearch: true,\n queryType: 'semantic',\n semanticOptions: {\n configurationName: params.semanticConfig,\n semanticQuery: params.semanticQuery,\n answers: params.enableAnswers,\n captions: params.enableCaptions,\n },\n });\n }\n\n /**\n * Convenience method for hybrid vector + text search. Combines the vector query with a\n * BM25 full-text query over `textQuery`, fused via Azure AI Search's native Reciprocal\n * Rank Fusion. No vectorizer needs to be configured on the index.\n *\n * @param params - Query parameters with a text query\n * @returns Array of search results from hybrid search\n */\n async hybridQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'textVectorization'> & {\n textQuery: string;\n /** Searchable text fields to match `textQuery` against. Defaults to the index's default searchable fields. */\n vectorFields?: string[];\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n textVectorization: {\n text: params.textQuery,\n fields: params.vectorFields,\n },\n });\n }\n\n /**\n * Convenience method for multi-vector search\n *\n * @param params - Query parameters with multiple vectors\n * @returns Array of search results from multi-vector search\n */\n async multiVectorQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'additionalVectorQueries'> & {\n vectors: Array<{\n vector: number[];\n weight?: number;\n fields?: string[];\n }>;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n additionalVectorQueries: params.vectors.map(v => ({\n vector: v.vector,\n weight: v.weight,\n fields: v.fields,\n kNearestNeighborsCount: params.topK,\n })),\n });\n }\n\n /**\n * Convenience method for exhaustive (exact) search\n *\n * @param params - Query parameters with exhaustive search enabled\n * @returns Array of search results from exhaustive search\n */\n async exactQuery(params: Omit<AzureAISearchAdvancedQueryParams, 'exhaustiveSearch'>): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n exhaustiveSearch: true,\n });\n }\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AzureKeyCredential, SearchClient, SearchIndexClient } from "@azure/search-documents";
2
2
  import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
3
3
  import { MastraVector } from "@mastra/core/vector";
4
- //#region src/vector/filter.ts
4
+ // src/vector/filter.ts
5
5
  /**
6
6
  * An OData predicate that no document can satisfy. Used wherever a filter is
7
7
  * syntactically valid but has nothing it could match (`$or: []`, `$in: []`,
@@ -116,8 +116,7 @@ var AzureAISearchFilterTranslator = class {
116
116
  return field;
117
117
  }
118
118
  };
119
- //#endregion
120
- //#region src/vector/index.ts
119
+ // src/vector/index.ts
121
120
  /**
122
121
  * Azure AI Search document keys may only contain letters, digits, `_`, `-` and `=`.
123
122
  * IDs that use anything else (e.g. `urn:uuid:...`, paths, emails) are base64url
@@ -1203,7 +1202,6 @@ var AzureAISearchVector = class AzureAISearchVector extends MastraVector {
1203
1202
  });
1204
1203
  }
1205
1204
  };
1206
- //#endregion
1207
1205
  export { AzureAISearchFilterTranslator, AzureAISearchVector };
1208
1206
 
1209
1207
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/vector/filter.ts","../src/vector/index.ts"],"sourcesContent":["import type { VectorFilter } from '@mastra/core/vector/filter';\n\n/**\n * Metadata filter accepted by `@mastra/azure-ai-search`.\n *\n * This is the standard Mastra filter shape (`$eq`, `$ne`, `$gt`, `$gte`,\n * `$lt`, `$lte`, `$in`, `$nin`, `$exists`, `$and`, `$or`, `$not`), which the\n * translator turns into an Azure AI Search OData `$filter` expression. Raw\n * OData is intentionally not accepted: the same filter selects documents for\n * `updateVector` and `deleteVectors`, so every predicate is built from\n * validated field names and escaped literals.\n */\nexport type AzureAISearchVectorFilter = VectorFilter;\n\n/**\n * An OData predicate that no document can satisfy. Used wherever a filter is\n * syntactically valid but has nothing it could match (`$or: []`, `$in: []`,\n * `field: []`). Returning `undefined` there would drop the filter entirely and\n * match every document, which is the wrong direction for a delete or update.\n * OData requires one side of a comparison to be a field, so this compares the\n * always-present key field against itself.\n */\nconst MATCH_NONE = \"(id eq '__mastra_none__' and id ne '__mastra_none__')\";\n\n/**\n * Translates Mastra vector filters to Azure AI Search OData filter syntax\n */\nexport class AzureAISearchFilterTranslator {\n /**\n * Translates a filter object to OData filter string\n * @param filter - The filter to translate\n * @returns OData filter string or undefined if no filter\n */\n translate(filter?: AzureAISearchVectorFilter): string | undefined {\n if (!filter) {\n return undefined;\n }\n\n const translated = this.translateMastraFilter(filter as Record<string, any>).trim();\n return translated.length > 0 ? translated : undefined;\n }\n\n private translateMastraFilter(filter: Record<string, any>): string {\n const conditions: string[] = [];\n\n for (const [key, value] of Object.entries(filter)) {\n if (key === '$and' && Array.isArray(value)) {\n // An empty $and is vacuously true, so it contributes no clause.\n const andConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n if (andConditions.length > 0) {\n conditions.push(`(${andConditions.join(' and ')})`);\n }\n continue;\n }\n\n if (key === '$or' && Array.isArray(value)) {\n const orConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n conditions.push(orConditions.length > 0 ? `(${orConditions.join(' or ')})` : MATCH_NONE);\n continue;\n }\n\n if (key === '$not' && typeof value === 'object' && value !== null) {\n const notCondition = this.translateMastraFilter(value);\n if (notCondition) {\n conditions.push(`not (${notCondition})`);\n }\n continue;\n }\n\n if (key.startsWith('$')) {\n throw new Error(`Unsupported filter operator '${key}'. Azure AI Search supports $and, $or, and $not.`);\n }\n\n conditions.push(...this.translateMastraFieldCondition(key, value));\n }\n\n return conditions.join(' and ');\n }\n\n private translateMastraFieldCondition(field: string, value: any): string[] {\n if (Array.isArray(value)) {\n return [this.formatInClause(field, value)];\n }\n\n if (value === null || value === undefined || typeof value !== 'object' || value instanceof Date) {\n return [`${this.escapeFieldName(field)} eq ${this.formatValue(value)}`];\n }\n\n const conditions: string[] = [];\n for (const [operator, operatorValue] of Object.entries(value)) {\n switch (operator) {\n case '$eq':\n conditions.push(`${this.escapeFieldName(field)} eq ${this.formatValue(operatorValue)}`);\n break;\n case '$ne':\n conditions.push(`${this.escapeFieldName(field)} ne ${this.formatValue(operatorValue)}`);\n break;\n case '$gt':\n conditions.push(`${this.escapeFieldName(field)} gt ${this.formatValue(operatorValue)}`);\n break;\n case '$gte':\n conditions.push(`${this.escapeFieldName(field)} ge ${this.formatValue(operatorValue)}`);\n break;\n case '$lt':\n conditions.push(`${this.escapeFieldName(field)} lt ${this.formatValue(operatorValue)}`);\n break;\n case '$lte':\n conditions.push(`${this.escapeFieldName(field)} le ${this.formatValue(operatorValue)}`);\n break;\n case '$in':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$in on field '${field}' requires an array`);\n }\n conditions.push(this.formatInClause(field, operatorValue));\n break;\n case '$nin':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$nin on field '${field}' requires an array`);\n }\n // \"not in nothing\" is true for every document, so it adds no clause.\n if (operatorValue.length > 0) {\n conditions.push(`not ${this.formatInClause(field, operatorValue)}`);\n }\n break;\n case '$exists':\n conditions.push(`${this.escapeFieldName(field)} ${operatorValue ? 'ne' : 'eq'} null`);\n break;\n case '$not': {\n const negatedConditions = this.translateMastraFieldCondition(field, operatorValue);\n if (negatedConditions.length > 0) {\n conditions.push(`not (${negatedConditions.join(' and ')})`);\n }\n break;\n }\n default:\n throw new Error(\n `Unsupported filter operator '${operator}' on field '${field}'. Azure AI Search supports $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $not.`,\n );\n }\n }\n return conditions;\n }\n\n /**\n * Builds a membership check as an OR-chain of equality comparisons.\n * OData's `in` keyword is not a real operator in Azure AI Search's filter\n * syntax (it only exists as the `search.in()` function, which needs its own\n * comma-escaping for values that may contain the separator), so membership\n * is expressed the portable way: `(field eq v1 or field eq v2 or ...)`.\n * An empty set can match nothing.\n */\n private formatInClause(field: string, values: any[]): string {\n const escapedField = this.escapeFieldName(field);\n if (values.length === 0) {\n return MATCH_NONE;\n }\n return `(${values.map(v => `${escapedField} eq ${this.formatValue(v)}`).join(' or ')})`;\n }\n\n private formatValue(value: any): string {\n if (typeof value === 'string') {\n // Escape single quotes in strings\n const escapedValue = value.replace(/'/g, \"''\");\n return `'${escapedValue}'`;\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'boolean') {\n return value.toString();\n }\n\n if (value === null || value === undefined) {\n return 'null';\n }\n\n return String(value);\n }\n\n private escapeFieldName(field: string): string {\n // Azure AI Search OData uses unquoted field paths (e.g., Address/City)\n // Validate field names to prevent OData injection\n if (!/^[a-zA-Z_][\\w/]*$/.test(field)) {\n throw new Error(`Invalid field name for OData filter: '${field}'`);\n }\n return field;\n }\n}\n","import type { TokenCredential } from '@azure/core-auth';\nimport type {\n VectorQuery,\n VectorSearchOptions,\n SemanticSearchOptions,\n SearchRequestOptions,\n VectorizedQuery,\n SearchClientOptions,\n} from '@azure/search-documents';\nimport { SearchClient, SearchIndexClient, AzureKeyCredential } from '@azure/search-documents';\nimport { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';\nimport type {\n CreateIndexParams,\n DeleteIndexParams,\n DeleteVectorParams,\n DescribeIndexParams,\n IndexStats,\n QueryResult,\n QueryVectorParams,\n UpdateVectorParams,\n UpsertVectorParams,\n} from '@mastra/core/vector';\nimport { MastraVector } from '@mastra/core/vector';\nimport type { AzureAISearchVectorFilter } from './filter';\nimport { AzureAISearchFilterTranslator } from './filter';\n\n/**\n * Configuration options for Azure AI Search vector store\n */\nexport interface AzureAISearchVectorOptions {\n /** The endpoint URL of your Azure AI Search service */\n endpoint: string;\n /** Authentication credential - either API key or Azure credential */\n credential: string | AzureKeyCredential | TokenCredential;\n /** API version (optional, defaults to latest) */\n apiVersion?: string;\n /**\n * Additional options for SearchClient (optional)\n * Use this to pass custom policies like AXET proxy, retry options, etc.\n *\n * @example\n * ```typescript\n * clientOptions: {\n * additionalPolicies: [{\n * position: 'perCall',\n * policy: createAxetProxyPolicy({ ... })\n * }]\n * }\n * ```\n */\n clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n /**\n * Automatically add a filterable field to the index the first time a top-level\n * string/number/boolean metadata key is seen in `upsert`/`updateVector`.\n *\n * Azure AI Search can only filter on fields declared in the index schema and has\n * no JSON-path filtering, so without this, `query({ filter: { thread_id } })` on a\n * key that was never declared via `metadataIndexes` fails with HTTP 400. Mastra\n * Memory relies on filtering by `thread_id`/`resource_id` without declaring them.\n *\n * Field type is inferred from the first value seen. Keys whose names are not valid\n * Azure field names (must match `^[A-Za-z][A-Za-z0-9_]*$`), or whose values are\n * arrays/objects/null, stay in the JSON `metadata` blob only and are not filterable.\n *\n * Defaults to `true`. Set to `false` to require explicit `metadataIndexes`.\n */\n autoIndexMetadata?: boolean;\n}\n\n/**\n * Azure AI Search document keys may only contain letters, digits, `_`, `-` and `=`.\n * IDs that use anything else (e.g. `urn:uuid:...`, paths, emails) are base64url\n * encoded behind a marker prefix and decoded back on every read path.\n */\nconst SAFE_DOCUMENT_KEY = /^[A-Za-z0-9_\\-=]+$/;\nconst ENCODED_KEY_PREFIX = 'b64-';\n\nfunction encodeDocumentKey(id: string): string {\n if (SAFE_DOCUMENT_KEY.test(id) && !id.startsWith(ENCODED_KEY_PREFIX)) {\n return id;\n }\n return ENCODED_KEY_PREFIX + Buffer.from(id, 'utf8').toString('base64url');\n}\n\nfunction decodeDocumentKey(key: string): string {\n if (!key.startsWith(ENCODED_KEY_PREFIX)) {\n return key;\n }\n return Buffer.from(key.slice(ENCODED_KEY_PREFIX.length), 'base64url').toString('utf8');\n}\n\n/** Azure AI Search field naming rules (letters/digits/underscore, must start with a letter, max 128 chars). */\nconst AZURE_FIELD_NAME = /^[A-Za-z][A-Za-z0-9_]{0,127}$/;\n\nfunction edmTypeForValue(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return 'Edm.String';\n case 'number':\n return Number.isFinite(value) ? 'Edm.Double' : undefined;\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return undefined;\n }\n}\n\nfunction valueMatchesEdmType(value: unknown, edmType: string | undefined): boolean {\n switch (edmType) {\n case 'Edm.String':\n return typeof value === 'string';\n case 'Edm.Double':\n case 'Edm.Int32':\n case 'Edm.Int64':\n return typeof value === 'number' && Number.isFinite(value);\n case 'Edm.Boolean':\n return typeof value === 'boolean';\n default:\n return false;\n }\n}\n\n/**\n * Azure AI Search document structure for vector storage\n */\ninterface AzureAISearchDocument {\n /** Unique identifier for the document */\n id: string;\n /** Vector embedding */\n vector: number[];\n /** Metadata associated with the document (stored as JSON string) */\n metadata: string;\n /** Optional content field */\n content?: string;\n}\n\n/**\n * Mapping of Mastra metrics to Azure AI Search vector similarity functions\n */\nconst METRIC_MAPPING = {\n cosine: 'cosine',\n euclidean: 'euclidean',\n dotproduct: 'dotProduct',\n} as const;\n\nexport type AzureAISearchQueryVectorParams = QueryVectorParams<AzureAISearchVectorFilter>;\n\ntype AzureAISearchUpsertParams = UpsertVectorParams & { deleteFilter?: AzureAISearchVectorFilter };\ntype AzureAISearchUpdateParams = UpdateVectorParams & { filter?: AzureAISearchVectorFilter };\ntype AzureAISearchDeleteVectorsParams = {\n indexName: string;\n ids?: string[];\n filter?: AzureAISearchVectorFilter;\n};\n\ninterface IndexSchema {\n vectorFieldName: string;\n dimension: number | undefined;\n fields: Map<string, IndexFieldCapabilities>;\n}\n\ntype IndexFieldCapabilities = {\n type?: string;\n};\n\nconst DEFAULT_DOCUMENT_FIELDS = new Set(['id', 'metadata', 'content']);\n\n/**\n * Extended index creation parameters for Azure AI Search specific features\n */\nexport interface AzureAISearchCreateIndexParams extends CreateIndexParams {\n /** Name of the vector field (defaults to 'vector') */\n vectorField?: string;\n /** Additional fields to include in the index schema */\n additionalFields?: Array<{\n name: string;\n type: string;\n searchable?: boolean;\n filterable?: boolean;\n retrievable?: boolean;\n sortable?: boolean;\n facetable?: boolean;\n key?: boolean;\n }>;\n /**\n * Metadata keys that should also be created as explicit filterable Azure AI Search fields.\n * A plain string declares a field as `Edm.String` (backward-compatible default). To filter\n * on a numeric or boolean metadata value with the correct Azure field type — required for\n * numeric comparisons like $gt/$gte/$lt/$lte to work, since Azure rejects an unquoted numeric\n * literal against an Edm.String field — pass `{ name, type }` instead.\n */\n metadataIndexes?: Array<string | { name: string; type: 'string' | 'number' | 'boolean' }>;\n /** HNSW algorithm parameters */\n hnswParameters?: {\n m?: number;\n efConstruction?: number;\n efSearch?: number;\n };\n /** Semantic search configuration */\n semanticConfig?: {\n name?: string;\n prioritizedFields?: {\n /** Single title field for semantic ranking */\n titleField?: { fieldName: string };\n /** Content fields for semantic ranking (renamed from contentFields) */\n prioritizedContentFields?: Array<{ fieldName: string }>;\n /** Keywords fields for semantic ranking (renamed from keywordsFields) */\n prioritizedKeywordsFields?: Array<{ fieldName: string }>;\n };\n };\n /**\n * Enable vector compression (quantization) on the index's vector field.\n * Required for the `oversampling` query parameter to have any effect —\n * Azure AI Search only allows oversampling when the vector field has a\n * compression configured, since oversampling compensates for the recall\n * lost to compression.\n */\n compression?: {\n /** Compression kind. Defaults to 'scalarQuantization'. */\n kind?: 'scalarQuantization' | 'binaryQuantization';\n };\n}\n\n/**\n * Extended query parameters for Azure AI Search advanced features\n */\nexport interface AzureAISearchAdvancedQueryParams extends AzureAISearchQueryVectorParams {\n /** Enable semantic search capabilities */\n useSemanticSearch?: boolean;\n /** Semantic search configuration */\n semanticOptions?: {\n /** Name of semantic configuration in the index */\n configurationName?: string;\n /** Separate query for semantic reranking */\n semanticQuery?: string;\n /** Enable answer extraction from documents */\n answers?: boolean;\n /** Enable caption extraction from documents */\n captions?: boolean;\n /** Maximum wait time for semantic processing (ms) */\n maxWaitTime?: number;\n };\n /** Use exhaustive k-NN search for exact results */\n exhaustiveSearch?: boolean;\n /** Oversampling factor for compressed vectors */\n oversampling?: number;\n /** Relative weight for this vector query in hybrid scenarios */\n weight?: number;\n /** Query type: simple, full, or semantic */\n queryType?: 'simple' | 'full' | 'semantic';\n /**\n * Combine a full-text query with the vector query for hybrid search.\n * Runs as native Azure AI Search hybrid search (BM25 full-text + vector,\n * fused via Reciprocal Rank Fusion) — no vectorizer needs to be configured\n * on the index, unlike Azure's server-side query vectorization.\n */\n textVectorization?: {\n /** Text to search for (BM25 full-text search term) */\n text: string;\n /** Searchable text fields to match against. Defaults to the index's default searchable fields (e.g. content). */\n fields?: string[];\n };\n /** Multiple vector queries for hybrid search */\n additionalVectorQueries?: Array<{\n vector: number[];\n fields?: string[];\n weight?: number;\n kNearestNeighborsCount?: number;\n }>;\n /** Vector filter mode: apply before or after vector search */\n filterMode?: 'preFilter' | 'postFilter';\n}\n\n/**\n * Azure AI Search vector store implementation for Mastra\n *\n * This implementation provides vector storage and similarity search capabilities\n * using Azure AI Search's vector search features.\n *\n * @example\n * ```typescript\n * const azureVector = new AzureAISearchVector({\n * id: 'azure-search-vectors',\n * endpoint: 'https://your-service.search.windows.net',\n * credential: 'your-api-key'\n * });\n *\n * // Create an index\n * await azureVector.createIndex({\n * indexName: 'products',\n * dimension: 1536,\n * metric: 'cosine'\n * });\n *\n * // Insert vectors\n * const ids = await azureVector.upsert({\n * indexName: 'products',\n * vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],\n * metadata: [{ category: 'electronics' }, { category: 'books' }]\n * });\n *\n * // Search vectors\n * const results = await azureVector.query({\n * indexName: 'products',\n * queryVector: [0.1, 0.2, ...],\n * topK: 5,\n * filter: { eq: { category: 'electronics' } }\n * });\n * ```\n */\nexport class AzureAISearchVector extends MastraVector<AzureAISearchVectorFilter> {\n private endpoint: string;\n private credential: string | AzureKeyCredential | TokenCredential;\n private apiVersion?: string;\n private clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n private indexClient: SearchIndexClient;\n private searchClients: Map<string, SearchClient<AzureAISearchDocument>> = new Map();\n private autoIndexMetadata: boolean;\n /**\n * Serializes schema updates per index within this process. `createOrUpdateIndex`\n * is last-writer-wins, so two concurrent upserts each adding a different new\n * metadata field would otherwise clobber each other's field.\n */\n private schemaUpdateQueues: Map<string, Promise<void>> = new Map();\n\n /**\n * Azure AI Search rejects indexing requests containing more than 1,000 documents\n * (and any request larger than 16 MB). Chunk large upload/merge/delete calls to\n * stay within these per-request limits.\n */\n private static readonly INDEXING_BATCH_SIZE = 1000;\n\n constructor({\n id,\n endpoint,\n credential,\n apiVersion,\n clientOptions,\n autoIndexMetadata = true,\n }: AzureAISearchVectorOptions & { id: string }) {\n super({ id });\n\n this.endpoint = endpoint;\n this.credential = credential;\n this.apiVersion = apiVersion;\n this.clientOptions = clientOptions;\n this.autoIndexMetadata = autoIndexMetadata;\n\n // Initialize the index client for managing indexes\n this.indexClient = new SearchIndexClient(\n endpoint,\n typeof credential === 'string' ? new AzureKeyCredential(credential) : credential,\n {\n apiVersion,\n ...clientOptions, // Apply client options to index client as well\n },\n );\n }\n\n /**\n * Static factory method for easier instantiation with connection string\n */\n static fromConnectionString(connectionString: string, options?: { id?: string; apiVersion?: string }) {\n const url = new URL(connectionString);\n const endpoint = url.origin;\n const apiKey = url.searchParams.get('api-key') || url.searchParams.get('key');\n\n if (!apiKey) {\n throw new Error('API key not found in connection string');\n }\n\n return new AzureAISearchVector({\n id: options?.id || 'azure-ai-search',\n endpoint,\n credential: apiKey,\n apiVersion: options?.apiVersion,\n });\n }\n\n /**\n * Gets or creates a search client for a specific index\n */\n private getSearchClient(indexName: string): SearchClient<AzureAISearchDocument> {\n if (!this.searchClients.has(indexName)) {\n const client = new SearchClient<AzureAISearchDocument>(\n this.endpoint,\n indexName,\n typeof this.credential === 'string' ? new AzureKeyCredential(this.credential) : this.credential,\n {\n apiVersion: this.apiVersion,\n ...this.clientOptions, // Merge custom client options\n },\n );\n this.searchClients.set(indexName, client);\n }\n return this.searchClients.get(indexName)!;\n }\n\n /**\n * Runs an indexing operation (upload/merge/delete) in batches that respect\n * Azure AI Search's 1,000-document per-request limit, aggregating the\n * per-document results across all batches.\n */\n private async runBatchedIndexing<R extends { succeeded: boolean; key: string; errorMessage?: string }>(\n documents: unknown[],\n operation: (batch: unknown[]) => Promise<{ results: R[] }>,\n ): Promise<R[]> {\n const results: R[] = [];\n for (let i = 0; i < documents.length; i += AzureAISearchVector.INDEXING_BATCH_SIZE) {\n const batch = documents.slice(i, i + AzureAISearchVector.INDEXING_BATCH_SIZE);\n const { results: batchResults } = await this.retryWhileSchemaPropagates(() => operation(batch));\n results.push(...batchResults);\n }\n return results;\n }\n\n /**\n * A field added with `createOrUpdateIndex` is not immediately visible to the\n * indexing endpoint; an upload issued right after can be rejected with\n * \"The property 'x' does not exist on type 'search.documentFields'\". Retry that\n * specific error briefly while the schema change propagates.\n */\n private async retryWhileSchemaPropagates<T>(operation: () => Promise<T>): Promise<T> {\n const maxAttempts = 20;\n const delayMs = 500;\n for (let attempt = 1; ; attempt++) {\n try {\n return await operation();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const schemaLag = /does not exist on type 'search\\.documentFields'/.test(message);\n if (!schemaLag || attempt >= maxAttempts) {\n throw error;\n }\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n }\n\n /**\n * Reads the index definition once and derives everything a write path needs\n * from it: the vector field name, its dimension, and per-field capabilities.\n * `@azure/search-documents` does not cache `getIndex`, so callers that need\n * more than one of these must share a single read.\n */\n private async readIndexSchema(indexName: string): Promise<IndexSchema> {\n const index = await this.indexClient.getIndex(indexName);\n return this.schemaFromIndex(index);\n }\n\n private schemaFromIndex(index: { fields?: unknown[] }): IndexSchema {\n const fields = new Map<string, IndexFieldCapabilities>();\n let vectorFieldName = 'vector';\n let dimension: number | undefined;\n\n for (const raw of index.fields ?? []) {\n const field = raw as { name: string; type: string; dimensions?: number; vectorSearchDimensions?: number };\n fields.set(field.name, { type: field.type });\n const dims = field.dimensions ?? field.vectorSearchDimensions;\n if (dimension === undefined && field.type === 'Collection(Edm.Single)' && dims) {\n vectorFieldName = field.name;\n dimension = dims;\n }\n }\n\n return { vectorFieldName, dimension, fields };\n }\n\n /**\n * Detects the vector field name in an existing index\n * Falls back to 'vector' for backward compatibility\n */\n private async getVectorFieldName(indexName: string): Promise<string> {\n try {\n return (await this.readIndexSchema(indexName)).vectorFieldName;\n } catch {\n // If we can't determine the vector field name, fall back to 'vector' for backward compatibility\n return 'vector';\n }\n }\n\n private getMetadataIndexFields(\n metadataIndexes: NonNullable<AzureAISearchCreateIndexParams['metadataIndexes']>,\n additionalFields: AzureAISearchCreateIndexParams['additionalFields'],\n ) {\n const edmTypeFor = (type?: 'string' | 'number' | 'boolean'): string => {\n switch (type) {\n case 'number':\n return 'Edm.Double';\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return 'Edm.String';\n }\n };\n\n const reservedFieldNames = new Set(['id', 'metadata', 'content', 'vector']);\n return metadataIndexes\n .map(entry => (typeof entry === 'string' ? { name: entry, type: 'string' as const } : entry))\n .filter(\n entry => !reservedFieldNames.has(entry.name) && !additionalFields?.some(field => field.name === entry.name),\n )\n .map(entry => ({\n name: entry.name,\n type: edmTypeFor(entry.type),\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n }));\n }\n\n private async ensureExistingIndexFields({\n indexName,\n fields,\n }: {\n indexName: string;\n fields: Array<Record<string, any>>;\n }): Promise<void> {\n if (fields.length === 0) {\n return;\n }\n\n const previous = this.schemaUpdateQueues.get(indexName) ?? Promise.resolve();\n const run = previous\n .catch(() => {})\n .then(async () => {\n // Re-read inside the lock so we merge onto whatever the previous update wrote.\n const existingIndex = (await this.indexClient.getIndex(indexName)) as any;\n const existingFieldNames = new Set((existingIndex.fields ?? []).map((field: any) => field.name));\n const missingFields = fields.filter(field => !existingFieldNames.has(field.name));\n\n if (missingFields.length === 0) {\n return;\n }\n\n await (this.indexClient as any).createOrUpdateIndex({\n ...existingIndex,\n fields: [...(existingIndex.fields ?? []), ...missingFields],\n });\n });\n this.schemaUpdateQueues.set(indexName, run);\n try {\n await run;\n } finally {\n if (this.schemaUpdateQueues.get(indexName) === run) {\n this.schemaUpdateQueues.delete(indexName);\n }\n }\n }\n\n /**\n * Adds a filterable field for every top-level scalar metadata key that the index\n * does not yet have, so that `filter: { key: value }` works without the caller\n * declaring the key up front. Mutates `fields` so the subsequent document build\n * writes the typed column. No-op when `autoIndexMetadata` is false.\n */\n private async ensureMetadataFields({\n indexName,\n metadataList,\n vectorFieldName,\n fields,\n }: {\n indexName: string;\n metadataList: Array<Record<string, any> | undefined>;\n vectorFieldName: string;\n fields: Map<string, IndexFieldCapabilities>;\n }): Promise<void> {\n if (!this.autoIndexMetadata) {\n return;\n }\n\n const missing = new Map<string, string>();\n for (const metadata of metadataList) {\n if (!metadata) continue;\n for (const [key, value] of Object.entries(metadata)) {\n if (fields.has(key) || missing.has(key)) continue;\n if (DEFAULT_DOCUMENT_FIELDS.has(key) || key === vectorFieldName) continue;\n // Names starting with \"azureSearch\" are reserved by the service.\n if (!AZURE_FIELD_NAME.test(key) || key.startsWith('azureSearch')) continue;\n const edmType = edmTypeForValue(value);\n if (!edmType) continue;\n missing.set(key, edmType);\n }\n }\n\n if (missing.size === 0) {\n return;\n }\n\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...missing].map(([name, type]) => ({\n name,\n type,\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n })),\n });\n\n // Another writer may have declared the field with a different type; re-read\n // the authoritative schema rather than trusting our inferred types.\n const refreshed = (await this.readIndexSchema(indexName)).fields;\n for (const [name, capability] of refreshed) {\n fields.set(name, capability);\n }\n }\n\n private buildDocumentFromMetadata({\n id,\n vector,\n vectorFieldName,\n metadata = {},\n fields,\n writeMetadata = true,\n }: {\n id: string;\n vector?: number[];\n vectorFieldName: string;\n metadata?: Record<string, any>;\n fields: Map<string, IndexFieldCapabilities>;\n writeMetadata?: boolean;\n }): Record<string, any> {\n const doc: Record<string, any> = { id };\n\n if (writeMetadata) {\n doc.metadata = JSON.stringify(metadata);\n }\n\n if (vector) {\n doc[vectorFieldName] = vector;\n }\n\n // `content` is derived from metadata, so whenever the metadata blob is\n // (re)written the column must follow it; otherwise a merge would keep a\n // stale value from the previous document.\n if (typeof metadata.content === 'string') {\n doc.content = metadata.content;\n } else if (writeMetadata) {\n doc.content = '';\n }\n\n for (const [fieldName, field] of fields.entries()) {\n if (DEFAULT_DOCUMENT_FIELDS.has(fieldName) || fieldName === vectorFieldName) {\n continue;\n }\n\n if (field.type === 'Collection(Edm.Single)') {\n continue;\n }\n\n // Only write the typed column when the JS value matches the column's Edm type.\n // Azure rejects the whole document otherwise (e.g. number into Edm.String:\n // \"Cannot convert the literal '0' to the expected type 'Edm.String'\"). The\n // JSON `metadata` blob remains the source of truth on read either way.\n if (Object.prototype.hasOwnProperty.call(metadata, fieldName)) {\n doc[fieldName] = valueMatchesEdmType(metadata[fieldName], field.type) ? metadata[fieldName] : null;\n }\n }\n\n return doc;\n }\n\n /**\n * Creates a new vector search index with the specified configuration\n *\n * @param params - Index creation parameters (supports both basic Mastra interface and Azure AI Search extended options)\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createIndex(params: CreateIndexParams | AzureAISearchCreateIndexParams): Promise<void> {\n const {\n indexName,\n dimension,\n metric = 'cosine',\n vectorField = 'vector',\n additionalFields = [],\n metadataIndexes = [],\n hnswParameters = {},\n semanticConfig,\n compression,\n } = params as AzureAISearchCreateIndexParams;\n\n if (!Number.isInteger(dimension) || dimension <= 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_INVALID_DIMENSION',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Dimension must be a positive integer',\n details: { indexName, dimension },\n });\n }\n\n try {\n const similarityFunction = METRIC_MAPPING[metric as keyof typeof METRIC_MAPPING];\n\n // Vector field configuration (customizable name).\n // Both `retrievable` and `hidden` are set: some API versions key retrievability\n // off `retrievable`, newer ones off `hidden` (inverted) — the service otherwise\n // silently defaults new vector fields to hidden/non-retrievable and `$select`ing\n // them for `includeVector` fails with \"'vector' is not a retrievable field\".\n const vectorFieldConfig = {\n name: vectorField,\n type: 'Collection(Edm.Single)',\n searchable: true,\n retrievable: true,\n hidden: false,\n vectorSearchDimensions: dimension,\n vectorSearchProfileName: 'vector-profile',\n };\n\n // Core default fields (aligned with other Mastra vector stores)\n const defaultFields = [\n {\n name: 'id',\n type: 'Edm.String',\n key: true,\n filterable: true,\n // Sortable so filter-based lookups can page past Azure's 100,000 $skip\n // ceiling using a stable ordered range scan (see findIdsByFilter).\n sortable: true,\n facetable: false,\n searchable: false,\n },\n vectorFieldConfig,\n {\n name: 'metadata',\n type: 'Edm.String',\n searchable: false,\n filterable: true,\n sortable: false,\n facetable: false,\n },\n {\n name: 'content',\n type: 'Edm.String',\n searchable: true,\n filterable: false,\n sortable: false,\n facetable: false,\n },\n ];\n\n // Merge default fields with additional fields (avoid duplicates)\n const existingFieldNames = new Set(defaultFields.map(f => f.name));\n const metadataIndexFields = this.getMetadataIndexFields(metadataIndexes, additionalFields);\n const allFields = [\n ...defaultFields,\n ...metadataIndexFields,\n ...additionalFields.filter(field => !existingFieldNames.has(field.name)),\n ];\n\n // HNSW parameters with customizable values\n const hnswConfig = {\n metric: similarityFunction,\n m: hnswParameters.m ?? 4,\n efConstruction: hnswParameters.efConstruction ?? 400,\n efSearch: hnswParameters.efSearch ?? 500,\n };\n\n const indexDefinition: any = {\n name: indexName,\n fields: allFields,\n vectorSearch: {\n profiles: [\n {\n name: 'vector-profile',\n algorithmConfigurationName: 'vector-algorithm',\n ...(compression && { compressionName: 'vector-compression' }),\n },\n ],\n algorithms: [\n {\n name: 'vector-algorithm',\n kind: 'hnsw',\n hnswParameters: hnswConfig,\n },\n ],\n ...(compression && {\n compressions: [\n {\n kind: compression.kind ?? 'scalarQuantization',\n compressionName: 'vector-compression',\n // Rescoring with full-precision vectors is what makes `oversampling`\n // meaningful: oversampling widens the initial (compressed) candidate\n // set so the rescore step has more to recover recall from.\n rescoringOptions: {\n enableRescoring: true,\n defaultOversampling: 10,\n },\n },\n ],\n }),\n },\n };\n\n // Add semantic search configuration if provided.\n // Note: the SDK's SearchIndex field is `semanticSearch`, not `semantic`, and its\n // SemanticField entries use `name`, not `fieldName` — an unrecognized top-level\n // property is silently dropped by the service rather than rejected, so a wrong\n // shape here does not surface as a createIndex error, only later as \"this index\n // must have valid semantic configurations defined\" from a semantic query.\n if (semanticConfig) {\n const prioritizedFields = semanticConfig.prioritizedFields ?? {\n titleField: { fieldName: 'content' },\n prioritizedContentFields: [{ fieldName: 'content' }],\n };\n indexDefinition.semanticSearch = {\n configurations: [\n {\n name: semanticConfig.name ?? 'default-semantic-config',\n prioritizedFields: {\n ...(prioritizedFields.titleField && {\n titleField: { name: prioritizedFields.titleField.fieldName },\n }),\n ...(prioritizedFields.prioritizedContentFields && {\n contentFields: prioritizedFields.prioritizedContentFields.map(f => ({ name: f.fieldName })),\n }),\n ...(prioritizedFields.prioritizedKeywordsFields && {\n keywordsFields: prioritizedFields.prioritizedKeywordsFields.map(f => ({ name: f.fieldName })),\n }),\n },\n },\n ],\n };\n }\n\n await this.indexClient.createIndex(indexDefinition as any);\n\n // Index created successfully\n } catch (error: any) {\n // Check if index already exists\n if (error?.statusCode === 409 || error?.message?.includes('already exists')) {\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...this.getMetadataIndexFields(metadataIndexes, additionalFields), ...additionalFields],\n });\n // Index already exists, that's fine\n return;\n }\n\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, dimension, metric },\n },\n error,\n );\n }\n }\n\n /**\n * Creates an advanced vector search index with full Azure AI Search capabilities\n *\n * @param params - Extended Azure AI Search index creation parameters\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createAdvancedIndex(params: AzureAISearchCreateIndexParams): Promise<void> {\n return this.createIndex(params);\n }\n\n /**\n * Lists all available indexes in the Azure AI Search service\n *\n * @returns Array of index names\n * @throws {MastraError} When listing indexes fails\n */\n async listIndexes(): Promise<string[]> {\n try {\n const indexes = [];\n const indexIterator = this.indexClient.listIndexes();\n\n for await (const index of indexIterator) {\n indexes.push(index.name);\n }\n\n return indexes;\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_LIST_INDEXES_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n },\n error,\n );\n }\n }\n\n /**\n * Retrieves statistics and configuration information about an index\n *\n * @param indexName - Name of the index to describe\n * @returns Index statistics including dimension, count, and metric\n * @throws {MastraError} When describing index fails\n */\n async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {\n try {\n // Get index definition\n const index = await this.indexClient.getIndex(indexName);\n\n // Get document count\n const searchClient = this.getSearchClient(indexName);\n const countResult = await searchClient.getDocumentsCount();\n\n const { dimension } = this.schemaFromIndex(index);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n\n // Extract metric from vector search configuration\n let metric: 'cosine' | 'euclidean' | 'dotproduct' = 'cosine';\n if (index.vectorSearch?.algorithms) {\n const algorithm = index.vectorSearch.algorithms[0] as any;\n if (algorithm?.hnswParameters?.metric) {\n const azureMetric = algorithm.hnswParameters.metric;\n // Reverse lookup\n const metricEntry = Object.entries(METRIC_MAPPING).find(([_, value]) => value === azureMetric);\n if (metricEntry) {\n metric = metricEntry[0] as 'cosine' | 'euclidean' | 'dotproduct';\n }\n }\n }\n\n return { dimension, count: countResult, metric };\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DESCRIBE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes an index and all its documents\n *\n * @param indexName - Name of the index to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {\n try {\n await this.indexClient.deleteIndex(indexName);\n\n // Remove cached search client\n this.searchClients.delete(indexName);\n\n // Index deleted successfully\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Inserts or updates vectors in the specified index\n *\n * @param indexName - Name of the index to upsert into\n * @param vectors - Array of vectors to upsert\n * @param metadata - Array of metadata objects corresponding to each vector\n * @param ids - Array of IDs corresponding to each vector (auto-generated if not provided)\n * @returns Array of IDs of the upserted vectors\n * @throws {MastraError} When upsert operation fails\n */\n async upsert({ indexName, vectors, metadata = [], ids, deleteFilter }: AzureAISearchUpsertParams): Promise<string[]> {\n if (!Array.isArray(vectors) || vectors.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_EMPTY_VECTORS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Cannot upsert an empty vectors array',\n details: { indexName },\n });\n }\n if (metadata.length > 0 && metadata.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_METADATA_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and metadata must have the same length. Got ${vectors.length} vectors and ${metadata.length} metadata entries.`,\n details: { indexName, vectorsLength: vectors.length, metadataLength: metadata.length },\n });\n }\n if (ids && ids.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_IDS_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and ids must have the same length. Got ${vectors.length} vectors and ${ids.length} ids.`,\n details: { indexName, vectorsLength: vectors.length, idsLength: ids.length },\n });\n }\n\n try {\n if (deleteFilter) {\n await this.deleteVectors({ indexName, filter: deleteFilter });\n }\n\n // One schema read gives us the vector field, its dimension, and field types.\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions(vectors, dimension);\n await this.ensureMetadataFields({ indexName, metadataList: metadata, vectorFieldName, fields });\n\n // Generate IDs if not provided\n const vectorIds = ids || vectors.map(() => crypto.randomUUID());\n\n // Prepare documents for upload using dynamic vector field\n const documents = vectors.map((vector: number[], i: number) =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(vectorIds[i]!),\n vector,\n vectorFieldName,\n metadata: metadata[i] || {},\n fields,\n }),\n );\n\n // Upload documents (batched to respect Azure's per-request limits)\n const searchClient = this.getSearchClient(indexName);\n const uploadResults = await this.runBatchedIndexing(documents, batch =>\n searchClient.uploadDocuments(batch as any),\n );\n\n // Check for failures\n const failures = uploadResults.filter(result => !result.succeeded);\n if (failures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: uploadResults.length,\n failedCount: failures.length,\n firstFailedKey: failures[0]?.key || 'unknown',\n firstFailedError: failures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${failures.length} of ${uploadResults.length} documents failed to upload`),\n );\n }\n\n return vectorIds;\n } catch (error) {\n // If it's already a MastraError (e.g., from partial failure above), re-throw it\n if (error instanceof MastraError) {\n throw error;\n }\n\n // Normalize error to Error instance to avoid unsafe casting\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n\n // Otherwise, wrap the error in a MastraError\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, vectorCount: vectors?.length || 0 },\n },\n normalizedError,\n );\n }\n }\n\n /**\n * Standard MastraVector query method - compatible with Memory integration\n *\n * @param params - Standard query parameters compatible with MastraVector interface\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async query(params: QueryVectorParams<AzureAISearchVectorFilter>): Promise<QueryResult[]> {\n return this.advancedQuery(params);\n }\n\n /**\n * Advanced vector similarity search with full Azure AI Search capabilities\n *\n * @param indexName - Name of the index to search\n * @param queryVector - Vector to search with\n * @param topK - Maximum number of results to return\n * @param filter - Optional filter to apply to the search\n * @param includeVector - Whether to include the vector in each result (requires an extra retrievable select)\n * @param useSemanticSearch - Enable semantic search for better relevance\n * @param semanticOptions - Configuration for semantic search features\n * @param exhaustiveSearch - Use exhaustive k-NN search for exact results\n * @param oversampling - Oversampling factor for compressed vectors\n * @param weight - Relative weight for this vector query in hybrid scenarios\n * @param queryType - Query type: simple, full, or semantic\n * @param textVectorization - Enable automatic text vectorization\n * @param additionalVectorQueries - Multiple vector queries for hybrid search\n * @param filterMode - Apply filters before or after vector search\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async advancedQuery({\n indexName,\n queryVector,\n filter,\n topK = 10,\n includeVector = false, // Kept for API compatibility but ignored due to Azure AI Search limitations\n useSemanticSearch = false,\n semanticOptions,\n exhaustiveSearch = false,\n oversampling,\n weight = 1.0,\n queryType = 'simple',\n textVectorization,\n additionalVectorQueries = [],\n filterMode = 'preFilter',\n }: AzureAISearchAdvancedQueryParams): Promise<QueryResult[]> {\n try {\n const searchClient = this.getSearchClient(indexName);\n\n // Detect vector field name\n const vectorFieldName = await this.getVectorFieldName(indexName);\n\n // Translate filter to OData syntax\n const odataFilter = this.transformFilter(filter);\n\n // Prepare primary vector query using dynamic field name\n const primaryVectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: queryVector as number[],\n kNearestNeighborsCount: topK,\n fields: [vectorFieldName],\n exhaustive: exhaustiveSearch,\n weight: weight,\n // Oversampling only makes sense for approximate (compressed) search — Azure\n // rejects the combination of oversampling and exhaustive search outright.\n ...(oversampling && !exhaustiveSearch && { oversampling }),\n };\n\n // Prepare additional vector queries for hybrid search\n const allVectorQueries: VectorQuery<any>[] = [primaryVectorQuery];\n\n // Add additional vector queries\n additionalVectorQueries.forEach(vq => {\n const vectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: vq.vector,\n kNearestNeighborsCount: vq.kNearestNeighborsCount || topK,\n fields: vq.fields || [vectorFieldName],\n weight: vq.weight || 1.0,\n exhaustive: exhaustiveSearch,\n };\n allVectorQueries.push(vectorQuery);\n });\n\n // Prepare vector search options\n const vectorSearchOptions: VectorSearchOptions<any> = {\n queries: allVectorQueries,\n filterMode: filterMode,\n };\n\n // Prepare field selection. The vector field is declared `retrievable: true`\n // in the index schema, so it can be selected back when explicitly requested.\n const selectFields = includeVector\n ? ['id', 'metadata', 'content', vectorFieldName]\n : ['id', 'metadata', 'content'];\n\n // Build search options\n let searchOptions: SearchRequestOptions<any> = {\n vectorSearchOptions,\n filter: odataFilter,\n top: topK,\n select: selectFields,\n // Combining a full-text `search` term with vectorSearchOptions makes Azure AI\n // Search run true hybrid search (BM25 + vector, fused via Reciprocal Rank Fusion)\n // in a single request. This needs no server-side vectorizer, unlike a\n // VectorizableTextQuery, which requires one to be configured on the index.\n ...(textVectorization?.fields && { searchFields: textVectorization.fields }),\n };\n\n // Add semantic search if enabled\n if (useSemanticSearch || queryType === 'semantic') {\n const semanticSearchOptions: SemanticSearchOptions = {\n configurationName: semanticOptions?.configurationName || 'default-semantic-config',\n ...(semanticOptions?.semanticQuery && { semanticQuery: semanticOptions.semanticQuery }),\n ...(semanticOptions?.answers && {\n answers: {\n answerType: 'extractive' as const,\n count: 3,\n threshold: 0.7,\n },\n }),\n ...(semanticOptions?.captions && {\n captions: {\n captionType: 'extractive' as const,\n highlight: true,\n },\n }),\n ...(semanticOptions?.maxWaitTime && { maxWaitInMilliseconds: semanticOptions.maxWaitTime }),\n };\n\n searchOptions = {\n ...searchOptions,\n queryType: 'semantic' as const,\n semanticSearchOptions,\n };\n } else {\n searchOptions = {\n ...searchOptions,\n queryType: queryType === 'full' ? ('full' as const) : ('simple' as const),\n };\n }\n\n // Perform search. A text query (from textVectorization.text) is passed as the\n // full-text search term rather than vectorized server-side, so hybrid search\n // works against any index without requiring a configured vectorizer.\n const searchResults = await searchClient.search(textVectorization?.text ?? '*', searchOptions as any);\n\n // Process results - Azure SDK returns object with .results property\n const results: QueryResult[] = [];\n for await (const result of searchResults.results) {\n if (result.document) {\n const queryResult: QueryResult = {\n id: decodeDocumentKey(result.document.id),\n score: result.score || 0,\n metadata: result.document.metadata\n ? (() => {\n try {\n return JSON.parse(result.document.metadata);\n } catch {\n return { _raw: result.document.metadata };\n }\n })()\n : {},\n document: result.document.content,\n ...(includeVector && { vector: (result.document as Record<string, any>)[vectorFieldName] }),\n };\n\n // Add semantic-specific fields if available\n if (result.rerankerScore) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.rerankerScore'] = result.rerankerScore;\n }\n if (result.captions && result.captions.length > 0) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.captions'] = result.captions;\n }\n if (result.highlights) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.highlights'] = result.highlights;\n }\n\n results.push(queryResult);\n }\n }\n\n return results;\n } catch (error) {\n const unknownField = this.unknownFilterField(error);\n if (unknownField) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_FILTER_UNKNOWN_FIELD',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Filter references metadata field '${unknownField}' which does not exist on index '${indexName}'. Azure AI Search can only filter on declared fields: either upsert at least one document carrying '${unknownField}' as a string/number/boolean value (autoIndexMetadata), or declare it via createIndex({ metadataIndexes: ['${unknownField}'] }).`,\n details: { indexName, field: unknownField },\n },\n error,\n );\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_QUERY_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, topK },\n },\n error,\n );\n }\n }\n\n /**\n * Updates a vector and/or its metadata by ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to update\n * @param update - Object containing vector and/or metadata updates\n * @throws {MastraError} When update operation fails\n */\n async updateVector({ indexName, id, filter, update }: AzureAISearchUpdateParams): Promise<void> {\n try {\n if (!update.vector && !update.metadata) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_NO_UPDATES',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'No updates provided',\n });\n }\n\n if (!id && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_ID_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either id or filter must be provided',\n });\n }\n\n if (id && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_ID_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot provide both id and filter - they are mutually exclusive',\n });\n }\n\n const searchClient = this.getSearchClient(indexName);\n\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n\n // Validate vector dimension if updating vector\n if (update.vector) {\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions([update.vector], dimension);\n }\n\n let targetIds: string[];\n if (id) {\n targetIds = [id];\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot update with empty filter',\n });\n }\n targetIds = await this.findIdsByFilter(indexName, filter);\n }\n\n if (targetIds.length === 0) {\n return;\n }\n\n if (update.metadata) {\n await this.ensureMetadataFields({ indexName, metadataList: [update.metadata], vectorFieldName, fields });\n }\n\n const updatedDocs = targetIds.map(targetId =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(targetId),\n vector: update.vector,\n vectorFieldName,\n metadata: update.metadata,\n fields,\n writeMetadata: Boolean(update.metadata),\n }),\n );\n\n // Merge documents (update operation, batched to respect Azure's per-request limits)\n const mergeResults = await this.runBatchedIndexing(updatedDocs, batch =>\n searchClient.mergeDocuments(batch as any),\n );\n\n // Check for per-document failures\n const mergeFailures = mergeResults.filter(result => !result.succeeded);\n if (mergeFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: mergeResults.length,\n failedCount: mergeFailures.length,\n firstFailedKey: mergeFailures[0]?.key || 'unknown',\n firstFailedError: mergeFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${mergeFailures.length} of ${mergeResults.length} documents failed to update`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, ...(id ? { id } : {}) },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes multiple vectors by IDs or metadata filter.\n */\n async deleteVectors({ indexName, ids, filter }: AzureAISearchDeleteVectorsParams): Promise<void> {\n try {\n if (ids && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_IDS_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot specify both ids and filter - they are mutually exclusive',\n });\n }\n\n if (!ids && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_IDS_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either filter or ids must be provided',\n });\n }\n\n let idsToDelete: string[];\n if (ids) {\n if (ids.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_IDS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty ids array',\n });\n }\n idsToDelete = ids;\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty filter',\n });\n }\n idsToDelete = await this.findIdsByFilter(indexName, filter);\n }\n\n if (idsToDelete.length === 0) {\n return;\n }\n\n const searchClient = this.getSearchClient(indexName);\n const deleteDocs = idsToDelete.map(id => ({ id: encodeDocumentKey(id) }));\n const deleteResults = await this.runBatchedIndexing(deleteDocs, batch =>\n searchClient.deleteDocuments(batch as any),\n );\n\n // Check for per-document failures\n const deleteFailures = deleteResults.filter(result => !result.succeeded);\n if (deleteFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: deleteResults.length,\n failedCount: deleteFailures.length,\n firstFailedKey: deleteFailures[0]?.key || 'unknown',\n firstFailedError: deleteFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${deleteFailures.length} of ${deleteResults.length} documents failed to delete`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTORS_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n idsCount: ids?.length || 0,\n hasFilter: !!filter,\n },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes a vector by its ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {\n try {\n const searchClient = this.getSearchClient(indexName);\n const deleteResult = await searchClient.deleteDocuments([{ id: encodeDocumentKey(id) }] as any);\n const deleteFailure = deleteResult.results.find(result => !result.succeeded);\n\n if (deleteFailure) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n id,\n failedKey: deleteFailure.key || 'unknown',\n error: deleteFailure.errorMessage || 'No error message',\n },\n },\n new Error(`Document ${deleteFailure.key || id} failed to delete`),\n );\n }\n } catch (error: unknown) {\n if (error instanceof MastraError) {\n throw error;\n }\n // Don't throw error if document doesn't exist (404)\n if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 404) {\n return;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, id },\n },\n error,\n );\n }\n }\n\n /**\n * Validates that all vectors have the correct dimension\n */\n private validateVectorDimensions(vectors: number[][], dimension: number): void {\n for (let i = 0; i < vectors.length; i++) {\n if (vectors[i]?.length !== dimension) {\n throw new Error(\n `Vector at index ${i} has invalid dimension ${vectors[i]?.length}. Expected ${dimension} dimensions.`,\n );\n }\n }\n }\n\n /**\n * Extracts the field name from Azure's \"Could not find a property named 'x'\" $filter error.\n */\n private unknownFilterField(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error);\n return /Could not find a property named '([^']+)'/.exec(message)?.[1];\n }\n\n /**\n * Transforms filter to Azure AI Search OData syntax\n */\n private transformFilter(filter?: AzureAISearchVectorFilter): string | undefined {\n const translator = new AzureAISearchFilterTranslator();\n return translator.translate(filter);\n }\n\n /**\n * Finds document IDs matching a filter.\n */\n private async findIdsByFilter(indexName: string, filter: AzureAISearchVectorFilter): Promise<string[]> {\n const searchClient = this.getSearchClient(indexName);\n const odataFilter = this.transformFilter(filter);\n // Only update/delete call this. A filter that is non-empty as an object but\n // translates to no predicate (`{ $and: [] }`, `{ x: { $nin: [] } }`) would\n // otherwise select every document, which is never what a caller meant.\n if (!odataFilter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Filter does not constrain any documents; refusing to apply it to every document',\n });\n }\n\n const ids: string[] = [];\n const pageSize = 1000;\n // Azure AI Search caps $skip at 100,000, so paginate with a stable\n // ordered range scan (\"search after\") on the sortable key field instead.\n let lastId: string | undefined;\n\n while (true) {\n const rangeClause = lastId !== undefined ? `id gt '${lastId.replace(/'/g, \"''\")}'` : undefined;\n const combinedFilter = [odataFilter ? `(${odataFilter})` : undefined, rangeClause].filter(Boolean).join(' and ');\n\n const searchResults = await searchClient.search('*', {\n filter: combinedFilter || undefined,\n top: pageSize,\n orderBy: ['id asc'],\n select: ['id'],\n } as any);\n\n let count = 0;\n for await (const result of searchResults.results) {\n if (result.document?.id) {\n ids.push(decodeDocumentKey(result.document.id));\n // Range-scan cursor must stay in stored (encoded) key space.\n lastId = result.document.id;\n }\n count++;\n }\n\n if (count < pageSize) {\n break;\n }\n }\n\n return ids;\n }\n\n /**\n * Convenience method for semantic search\n *\n * @param params - Query parameters with semantic search enabled\n * @returns Array of search results with semantic enhancements\n */\n async semanticQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'useSemanticSearch' | 'queryType' | 'semanticOptions'> & {\n semanticConfig?: string;\n semanticQuery?: string;\n enableAnswers?: boolean;\n enableCaptions?: boolean;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n useSemanticSearch: true,\n queryType: 'semantic',\n semanticOptions: {\n configurationName: params.semanticConfig,\n semanticQuery: params.semanticQuery,\n answers: params.enableAnswers,\n captions: params.enableCaptions,\n },\n });\n }\n\n /**\n * Convenience method for hybrid vector + text search. Combines the vector query with a\n * BM25 full-text query over `textQuery`, fused via Azure AI Search's native Reciprocal\n * Rank Fusion. No vectorizer needs to be configured on the index.\n *\n * @param params - Query parameters with a text query\n * @returns Array of search results from hybrid search\n */\n async hybridQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'textVectorization'> & {\n textQuery: string;\n /** Searchable text fields to match `textQuery` against. Defaults to the index's default searchable fields. */\n vectorFields?: string[];\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n textVectorization: {\n text: params.textQuery,\n fields: params.vectorFields,\n },\n });\n }\n\n /**\n * Convenience method for multi-vector search\n *\n * @param params - Query parameters with multiple vectors\n * @returns Array of search results from multi-vector search\n */\n async multiVectorQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'additionalVectorQueries'> & {\n vectors: Array<{\n vector: number[];\n weight?: number;\n fields?: string[];\n }>;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n additionalVectorQueries: params.vectors.map(v => ({\n vector: v.vector,\n weight: v.weight,\n fields: v.fields,\n kNearestNeighborsCount: params.topK,\n })),\n });\n }\n\n /**\n * Convenience method for exhaustive (exact) search\n *\n * @param params - Query parameters with exhaustive search enabled\n * @returns Array of search results from exhaustive search\n */\n async exactQuery(params: Omit<AzureAISearchAdvancedQueryParams, 'exhaustiveSearch'>): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n exhaustiveSearch: true,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/vector/filter.ts","../src/vector/index.ts"],"sourcesContent":["import type { VectorFilter } from '@mastra/core/vector/filter';\n\n/**\n * Metadata filter accepted by `@mastra/azure-ai-search`.\n *\n * This is the standard Mastra filter shape (`$eq`, `$ne`, `$gt`, `$gte`,\n * `$lt`, `$lte`, `$in`, `$nin`, `$exists`, `$and`, `$or`, `$not`), which the\n * translator turns into an Azure AI Search OData `$filter` expression. Raw\n * OData is intentionally not accepted: the same filter selects documents for\n * `updateVector` and `deleteVectors`, so every predicate is built from\n * validated field names and escaped literals.\n */\nexport type AzureAISearchVectorFilter = VectorFilter;\n\n/**\n * An OData predicate that no document can satisfy. Used wherever a filter is\n * syntactically valid but has nothing it could match (`$or: []`, `$in: []`,\n * `field: []`). Returning `undefined` there would drop the filter entirely and\n * match every document, which is the wrong direction for a delete or update.\n * OData requires one side of a comparison to be a field, so this compares the\n * always-present key field against itself.\n */\nconst MATCH_NONE = \"(id eq '__mastra_none__' and id ne '__mastra_none__')\";\n\n/**\n * Translates Mastra vector filters to Azure AI Search OData filter syntax\n */\nexport class AzureAISearchFilterTranslator {\n /**\n * Translates a filter object to OData filter string\n * @param filter - The filter to translate\n * @returns OData filter string or undefined if no filter\n */\n translate(filter?: AzureAISearchVectorFilter): string | undefined {\n if (!filter) {\n return undefined;\n }\n\n const translated = this.translateMastraFilter(filter as Record<string, any>).trim();\n return translated.length > 0 ? translated : undefined;\n }\n\n private translateMastraFilter(filter: Record<string, any>): string {\n const conditions: string[] = [];\n\n for (const [key, value] of Object.entries(filter)) {\n if (key === '$and' && Array.isArray(value)) {\n // An empty $and is vacuously true, so it contributes no clause.\n const andConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n if (andConditions.length > 0) {\n conditions.push(`(${andConditions.join(' and ')})`);\n }\n continue;\n }\n\n if (key === '$or' && Array.isArray(value)) {\n const orConditions = value.map(item => this.translateMastraFilter(item)).filter(Boolean);\n conditions.push(orConditions.length > 0 ? `(${orConditions.join(' or ')})` : MATCH_NONE);\n continue;\n }\n\n if (key === '$not' && typeof value === 'object' && value !== null) {\n const notCondition = this.translateMastraFilter(value);\n if (notCondition) {\n conditions.push(`not (${notCondition})`);\n }\n continue;\n }\n\n if (key.startsWith('$')) {\n throw new Error(`Unsupported filter operator '${key}'. Azure AI Search supports $and, $or, and $not.`);\n }\n\n conditions.push(...this.translateMastraFieldCondition(key, value));\n }\n\n return conditions.join(' and ');\n }\n\n private translateMastraFieldCondition(field: string, value: any): string[] {\n if (Array.isArray(value)) {\n return [this.formatInClause(field, value)];\n }\n\n if (value === null || value === undefined || typeof value !== 'object' || value instanceof Date) {\n return [`${this.escapeFieldName(field)} eq ${this.formatValue(value)}`];\n }\n\n const conditions: string[] = [];\n for (const [operator, operatorValue] of Object.entries(value)) {\n switch (operator) {\n case '$eq':\n conditions.push(`${this.escapeFieldName(field)} eq ${this.formatValue(operatorValue)}`);\n break;\n case '$ne':\n conditions.push(`${this.escapeFieldName(field)} ne ${this.formatValue(operatorValue)}`);\n break;\n case '$gt':\n conditions.push(`${this.escapeFieldName(field)} gt ${this.formatValue(operatorValue)}`);\n break;\n case '$gte':\n conditions.push(`${this.escapeFieldName(field)} ge ${this.formatValue(operatorValue)}`);\n break;\n case '$lt':\n conditions.push(`${this.escapeFieldName(field)} lt ${this.formatValue(operatorValue)}`);\n break;\n case '$lte':\n conditions.push(`${this.escapeFieldName(field)} le ${this.formatValue(operatorValue)}`);\n break;\n case '$in':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$in on field '${field}' requires an array`);\n }\n conditions.push(this.formatInClause(field, operatorValue));\n break;\n case '$nin':\n if (!Array.isArray(operatorValue)) {\n throw new Error(`$nin on field '${field}' requires an array`);\n }\n // \"not in nothing\" is true for every document, so it adds no clause.\n if (operatorValue.length > 0) {\n conditions.push(`not ${this.formatInClause(field, operatorValue)}`);\n }\n break;\n case '$exists':\n conditions.push(`${this.escapeFieldName(field)} ${operatorValue ? 'ne' : 'eq'} null`);\n break;\n case '$not': {\n const negatedConditions = this.translateMastraFieldCondition(field, operatorValue);\n if (negatedConditions.length > 0) {\n conditions.push(`not (${negatedConditions.join(' and ')})`);\n }\n break;\n }\n default:\n throw new Error(\n `Unsupported filter operator '${operator}' on field '${field}'. Azure AI Search supports $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $not.`,\n );\n }\n }\n return conditions;\n }\n\n /**\n * Builds a membership check as an OR-chain of equality comparisons.\n * OData's `in` keyword is not a real operator in Azure AI Search's filter\n * syntax (it only exists as the `search.in()` function, which needs its own\n * comma-escaping for values that may contain the separator), so membership\n * is expressed the portable way: `(field eq v1 or field eq v2 or ...)`.\n * An empty set can match nothing.\n */\n private formatInClause(field: string, values: any[]): string {\n const escapedField = this.escapeFieldName(field);\n if (values.length === 0) {\n return MATCH_NONE;\n }\n return `(${values.map(v => `${escapedField} eq ${this.formatValue(v)}`).join(' or ')})`;\n }\n\n private formatValue(value: any): string {\n if (typeof value === 'string') {\n // Escape single quotes in strings\n const escapedValue = value.replace(/'/g, \"''\");\n return `'${escapedValue}'`;\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'boolean') {\n return value.toString();\n }\n\n if (value === null || value === undefined) {\n return 'null';\n }\n\n return String(value);\n }\n\n private escapeFieldName(field: string): string {\n // Azure AI Search OData uses unquoted field paths (e.g., Address/City)\n // Validate field names to prevent OData injection\n if (!/^[a-zA-Z_][\\w/]*$/.test(field)) {\n throw new Error(`Invalid field name for OData filter: '${field}'`);\n }\n return field;\n }\n}\n","import type { TokenCredential } from '@azure/core-auth';\nimport type {\n VectorQuery,\n VectorSearchOptions,\n SemanticSearchOptions,\n SearchRequestOptions,\n VectorizedQuery,\n SearchClientOptions,\n} from '@azure/search-documents';\nimport { SearchClient, SearchIndexClient, AzureKeyCredential } from '@azure/search-documents';\nimport { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';\nimport type {\n CreateIndexParams,\n DeleteIndexParams,\n DeleteVectorParams,\n DescribeIndexParams,\n IndexStats,\n QueryResult,\n QueryVectorParams,\n UpdateVectorParams,\n UpsertVectorParams,\n} from '@mastra/core/vector';\nimport { MastraVector } from '@mastra/core/vector';\nimport type { AzureAISearchVectorFilter } from './filter';\nimport { AzureAISearchFilterTranslator } from './filter';\n\n/**\n * Configuration options for Azure AI Search vector store\n */\nexport interface AzureAISearchVectorOptions {\n /** The endpoint URL of your Azure AI Search service */\n endpoint: string;\n /** Authentication credential - either API key or Azure credential */\n credential: string | AzureKeyCredential | TokenCredential;\n /** API version (optional, defaults to latest) */\n apiVersion?: string;\n /**\n * Additional options for SearchClient (optional)\n * Use this to pass custom policies like AXET proxy, retry options, etc.\n *\n * @example\n * ```typescript\n * clientOptions: {\n * additionalPolicies: [{\n * position: 'perCall',\n * policy: createAxetProxyPolicy({ ... })\n * }]\n * }\n * ```\n */\n clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n /**\n * Automatically add a filterable field to the index the first time a top-level\n * string/number/boolean metadata key is seen in `upsert`/`updateVector`.\n *\n * Azure AI Search can only filter on fields declared in the index schema and has\n * no JSON-path filtering, so without this, `query({ filter: { thread_id } })` on a\n * key that was never declared via `metadataIndexes` fails with HTTP 400. Mastra\n * Memory relies on filtering by `thread_id`/`resource_id` without declaring them.\n *\n * Field type is inferred from the first value seen. Keys whose names are not valid\n * Azure field names (must match `^[A-Za-z][A-Za-z0-9_]*$`), or whose values are\n * arrays/objects/null, stay in the JSON `metadata` blob only and are not filterable.\n *\n * Defaults to `true`. Set to `false` to require explicit `metadataIndexes`.\n */\n autoIndexMetadata?: boolean;\n}\n\n/**\n * Azure AI Search document keys may only contain letters, digits, `_`, `-` and `=`.\n * IDs that use anything else (e.g. `urn:uuid:...`, paths, emails) are base64url\n * encoded behind a marker prefix and decoded back on every read path.\n */\nconst SAFE_DOCUMENT_KEY = /^[A-Za-z0-9_\\-=]+$/;\nconst ENCODED_KEY_PREFIX = 'b64-';\n\nfunction encodeDocumentKey(id: string): string {\n if (SAFE_DOCUMENT_KEY.test(id) && !id.startsWith(ENCODED_KEY_PREFIX)) {\n return id;\n }\n return ENCODED_KEY_PREFIX + Buffer.from(id, 'utf8').toString('base64url');\n}\n\nfunction decodeDocumentKey(key: string): string {\n if (!key.startsWith(ENCODED_KEY_PREFIX)) {\n return key;\n }\n return Buffer.from(key.slice(ENCODED_KEY_PREFIX.length), 'base64url').toString('utf8');\n}\n\n/** Azure AI Search field naming rules (letters/digits/underscore, must start with a letter, max 128 chars). */\nconst AZURE_FIELD_NAME = /^[A-Za-z][A-Za-z0-9_]{0,127}$/;\n\nfunction edmTypeForValue(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return 'Edm.String';\n case 'number':\n return Number.isFinite(value) ? 'Edm.Double' : undefined;\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return undefined;\n }\n}\n\nfunction valueMatchesEdmType(value: unknown, edmType: string | undefined): boolean {\n switch (edmType) {\n case 'Edm.String':\n return typeof value === 'string';\n case 'Edm.Double':\n case 'Edm.Int32':\n case 'Edm.Int64':\n return typeof value === 'number' && Number.isFinite(value);\n case 'Edm.Boolean':\n return typeof value === 'boolean';\n default:\n return false;\n }\n}\n\n/**\n * Azure AI Search document structure for vector storage\n */\ninterface AzureAISearchDocument {\n /** Unique identifier for the document */\n id: string;\n /** Vector embedding */\n vector: number[];\n /** Metadata associated with the document (stored as JSON string) */\n metadata: string;\n /** Optional content field */\n content?: string;\n}\n\n/**\n * Mapping of Mastra metrics to Azure AI Search vector similarity functions\n */\nconst METRIC_MAPPING = {\n cosine: 'cosine',\n euclidean: 'euclidean',\n dotproduct: 'dotProduct',\n} as const;\n\nexport type AzureAISearchQueryVectorParams = QueryVectorParams<AzureAISearchVectorFilter>;\n\ntype AzureAISearchUpsertParams = UpsertVectorParams & { deleteFilter?: AzureAISearchVectorFilter };\ntype AzureAISearchUpdateParams = UpdateVectorParams & { filter?: AzureAISearchVectorFilter };\ntype AzureAISearchDeleteVectorsParams = {\n indexName: string;\n ids?: string[];\n filter?: AzureAISearchVectorFilter;\n};\n\ninterface IndexSchema {\n vectorFieldName: string;\n dimension: number | undefined;\n fields: Map<string, IndexFieldCapabilities>;\n}\n\ntype IndexFieldCapabilities = {\n type?: string;\n};\n\nconst DEFAULT_DOCUMENT_FIELDS = new Set(['id', 'metadata', 'content']);\n\n/**\n * Extended index creation parameters for Azure AI Search specific features\n */\nexport interface AzureAISearchCreateIndexParams extends CreateIndexParams {\n /** Name of the vector field (defaults to 'vector') */\n vectorField?: string;\n /** Additional fields to include in the index schema */\n additionalFields?: Array<{\n name: string;\n type: string;\n searchable?: boolean;\n filterable?: boolean;\n retrievable?: boolean;\n sortable?: boolean;\n facetable?: boolean;\n key?: boolean;\n }>;\n /**\n * Metadata keys that should also be created as explicit filterable Azure AI Search fields.\n * A plain string declares a field as `Edm.String` (backward-compatible default). To filter\n * on a numeric or boolean metadata value with the correct Azure field type — required for\n * numeric comparisons like $gt/$gte/$lt/$lte to work, since Azure rejects an unquoted numeric\n * literal against an Edm.String field — pass `{ name, type }` instead.\n */\n metadataIndexes?: Array<string | { name: string; type: 'string' | 'number' | 'boolean' }>;\n /** HNSW algorithm parameters */\n hnswParameters?: {\n m?: number;\n efConstruction?: number;\n efSearch?: number;\n };\n /** Semantic search configuration */\n semanticConfig?: {\n name?: string;\n prioritizedFields?: {\n /** Single title field for semantic ranking */\n titleField?: { fieldName: string };\n /** Content fields for semantic ranking (renamed from contentFields) */\n prioritizedContentFields?: Array<{ fieldName: string }>;\n /** Keywords fields for semantic ranking (renamed from keywordsFields) */\n prioritizedKeywordsFields?: Array<{ fieldName: string }>;\n };\n };\n /**\n * Enable vector compression (quantization) on the index's vector field.\n * Required for the `oversampling` query parameter to have any effect —\n * Azure AI Search only allows oversampling when the vector field has a\n * compression configured, since oversampling compensates for the recall\n * lost to compression.\n */\n compression?: {\n /** Compression kind. Defaults to 'scalarQuantization'. */\n kind?: 'scalarQuantization' | 'binaryQuantization';\n };\n}\n\n/**\n * Extended query parameters for Azure AI Search advanced features\n */\nexport interface AzureAISearchAdvancedQueryParams extends AzureAISearchQueryVectorParams {\n /** Enable semantic search capabilities */\n useSemanticSearch?: boolean;\n /** Semantic search configuration */\n semanticOptions?: {\n /** Name of semantic configuration in the index */\n configurationName?: string;\n /** Separate query for semantic reranking */\n semanticQuery?: string;\n /** Enable answer extraction from documents */\n answers?: boolean;\n /** Enable caption extraction from documents */\n captions?: boolean;\n /** Maximum wait time for semantic processing (ms) */\n maxWaitTime?: number;\n };\n /** Use exhaustive k-NN search for exact results */\n exhaustiveSearch?: boolean;\n /** Oversampling factor for compressed vectors */\n oversampling?: number;\n /** Relative weight for this vector query in hybrid scenarios */\n weight?: number;\n /** Query type: simple, full, or semantic */\n queryType?: 'simple' | 'full' | 'semantic';\n /**\n * Combine a full-text query with the vector query for hybrid search.\n * Runs as native Azure AI Search hybrid search (BM25 full-text + vector,\n * fused via Reciprocal Rank Fusion) — no vectorizer needs to be configured\n * on the index, unlike Azure's server-side query vectorization.\n */\n textVectorization?: {\n /** Text to search for (BM25 full-text search term) */\n text: string;\n /** Searchable text fields to match against. Defaults to the index's default searchable fields (e.g. content). */\n fields?: string[];\n };\n /** Multiple vector queries for hybrid search */\n additionalVectorQueries?: Array<{\n vector: number[];\n fields?: string[];\n weight?: number;\n kNearestNeighborsCount?: number;\n }>;\n /** Vector filter mode: apply before or after vector search */\n filterMode?: 'preFilter' | 'postFilter';\n}\n\n/**\n * Azure AI Search vector store implementation for Mastra\n *\n * This implementation provides vector storage and similarity search capabilities\n * using Azure AI Search's vector search features.\n *\n * @example\n * ```typescript\n * const azureVector = new AzureAISearchVector({\n * id: 'azure-search-vectors',\n * endpoint: 'https://your-service.search.windows.net',\n * credential: 'your-api-key'\n * });\n *\n * // Create an index\n * await azureVector.createIndex({\n * indexName: 'products',\n * dimension: 1536,\n * metric: 'cosine'\n * });\n *\n * // Insert vectors\n * const ids = await azureVector.upsert({\n * indexName: 'products',\n * vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],\n * metadata: [{ category: 'electronics' }, { category: 'books' }]\n * });\n *\n * // Search vectors\n * const results = await azureVector.query({\n * indexName: 'products',\n * queryVector: [0.1, 0.2, ...],\n * topK: 5,\n * filter: { eq: { category: 'electronics' } }\n * });\n * ```\n */\nexport class AzureAISearchVector extends MastraVector<AzureAISearchVectorFilter> {\n private endpoint: string;\n private credential: string | AzureKeyCredential | TokenCredential;\n private apiVersion?: string;\n private clientOptions?: Omit<SearchClientOptions, 'apiVersion'>;\n private indexClient: SearchIndexClient;\n private searchClients: Map<string, SearchClient<AzureAISearchDocument>> = new Map();\n private autoIndexMetadata: boolean;\n /**\n * Serializes schema updates per index within this process. `createOrUpdateIndex`\n * is last-writer-wins, so two concurrent upserts each adding a different new\n * metadata field would otherwise clobber each other's field.\n */\n private schemaUpdateQueues: Map<string, Promise<void>> = new Map();\n\n /**\n * Azure AI Search rejects indexing requests containing more than 1,000 documents\n * (and any request larger than 16 MB). Chunk large upload/merge/delete calls to\n * stay within these per-request limits.\n */\n private static readonly INDEXING_BATCH_SIZE = 1000;\n\n constructor({\n id,\n endpoint,\n credential,\n apiVersion,\n clientOptions,\n autoIndexMetadata = true,\n }: AzureAISearchVectorOptions & { id: string }) {\n super({ id });\n\n this.endpoint = endpoint;\n this.credential = credential;\n this.apiVersion = apiVersion;\n this.clientOptions = clientOptions;\n this.autoIndexMetadata = autoIndexMetadata;\n\n // Initialize the index client for managing indexes\n this.indexClient = new SearchIndexClient(\n endpoint,\n typeof credential === 'string' ? new AzureKeyCredential(credential) : credential,\n {\n apiVersion,\n ...clientOptions, // Apply client options to index client as well\n },\n );\n }\n\n /**\n * Static factory method for easier instantiation with connection string\n */\n static fromConnectionString(connectionString: string, options?: { id?: string; apiVersion?: string }) {\n const url = new URL(connectionString);\n const endpoint = url.origin;\n const apiKey = url.searchParams.get('api-key') || url.searchParams.get('key');\n\n if (!apiKey) {\n throw new Error('API key not found in connection string');\n }\n\n return new AzureAISearchVector({\n id: options?.id || 'azure-ai-search',\n endpoint,\n credential: apiKey,\n apiVersion: options?.apiVersion,\n });\n }\n\n /**\n * Gets or creates a search client for a specific index\n */\n private getSearchClient(indexName: string): SearchClient<AzureAISearchDocument> {\n if (!this.searchClients.has(indexName)) {\n const client = new SearchClient<AzureAISearchDocument>(\n this.endpoint,\n indexName,\n typeof this.credential === 'string' ? new AzureKeyCredential(this.credential) : this.credential,\n {\n apiVersion: this.apiVersion,\n ...this.clientOptions, // Merge custom client options\n },\n );\n this.searchClients.set(indexName, client);\n }\n return this.searchClients.get(indexName)!;\n }\n\n /**\n * Runs an indexing operation (upload/merge/delete) in batches that respect\n * Azure AI Search's 1,000-document per-request limit, aggregating the\n * per-document results across all batches.\n */\n private async runBatchedIndexing<R extends { succeeded: boolean; key: string; errorMessage?: string }>(\n documents: unknown[],\n operation: (batch: unknown[]) => Promise<{ results: R[] }>,\n ): Promise<R[]> {\n const results: R[] = [];\n for (let i = 0; i < documents.length; i += AzureAISearchVector.INDEXING_BATCH_SIZE) {\n const batch = documents.slice(i, i + AzureAISearchVector.INDEXING_BATCH_SIZE);\n const { results: batchResults } = await this.retryWhileSchemaPropagates(() => operation(batch));\n results.push(...batchResults);\n }\n return results;\n }\n\n /**\n * A field added with `createOrUpdateIndex` is not immediately visible to the\n * indexing endpoint; an upload issued right after can be rejected with\n * \"The property 'x' does not exist on type 'search.documentFields'\". Retry that\n * specific error briefly while the schema change propagates.\n */\n private async retryWhileSchemaPropagates<T>(operation: () => Promise<T>): Promise<T> {\n const maxAttempts = 20;\n const delayMs = 500;\n for (let attempt = 1; ; attempt++) {\n try {\n return await operation();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const schemaLag = /does not exist on type 'search\\.documentFields'/.test(message);\n if (!schemaLag || attempt >= maxAttempts) {\n throw error;\n }\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n }\n\n /**\n * Reads the index definition once and derives everything a write path needs\n * from it: the vector field name, its dimension, and per-field capabilities.\n * `@azure/search-documents` does not cache `getIndex`, so callers that need\n * more than one of these must share a single read.\n */\n private async readIndexSchema(indexName: string): Promise<IndexSchema> {\n const index = await this.indexClient.getIndex(indexName);\n return this.schemaFromIndex(index);\n }\n\n private schemaFromIndex(index: { fields?: unknown[] }): IndexSchema {\n const fields = new Map<string, IndexFieldCapabilities>();\n let vectorFieldName = 'vector';\n let dimension: number | undefined;\n\n for (const raw of index.fields ?? []) {\n const field = raw as { name: string; type: string; dimensions?: number; vectorSearchDimensions?: number };\n fields.set(field.name, { type: field.type });\n const dims = field.dimensions ?? field.vectorSearchDimensions;\n if (dimension === undefined && field.type === 'Collection(Edm.Single)' && dims) {\n vectorFieldName = field.name;\n dimension = dims;\n }\n }\n\n return { vectorFieldName, dimension, fields };\n }\n\n /**\n * Detects the vector field name in an existing index\n * Falls back to 'vector' for backward compatibility\n */\n private async getVectorFieldName(indexName: string): Promise<string> {\n try {\n return (await this.readIndexSchema(indexName)).vectorFieldName;\n } catch {\n // If we can't determine the vector field name, fall back to 'vector' for backward compatibility\n return 'vector';\n }\n }\n\n private getMetadataIndexFields(\n metadataIndexes: NonNullable<AzureAISearchCreateIndexParams['metadataIndexes']>,\n additionalFields: AzureAISearchCreateIndexParams['additionalFields'],\n ) {\n const edmTypeFor = (type?: 'string' | 'number' | 'boolean'): string => {\n switch (type) {\n case 'number':\n return 'Edm.Double';\n case 'boolean':\n return 'Edm.Boolean';\n default:\n return 'Edm.String';\n }\n };\n\n const reservedFieldNames = new Set(['id', 'metadata', 'content', 'vector']);\n return metadataIndexes\n .map(entry => (typeof entry === 'string' ? { name: entry, type: 'string' as const } : entry))\n .filter(\n entry => !reservedFieldNames.has(entry.name) && !additionalFields?.some(field => field.name === entry.name),\n )\n .map(entry => ({\n name: entry.name,\n type: edmTypeFor(entry.type),\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n }));\n }\n\n private async ensureExistingIndexFields({\n indexName,\n fields,\n }: {\n indexName: string;\n fields: Array<Record<string, any>>;\n }): Promise<void> {\n if (fields.length === 0) {\n return;\n }\n\n const previous = this.schemaUpdateQueues.get(indexName) ?? Promise.resolve();\n const run = previous\n .catch(() => {})\n .then(async () => {\n // Re-read inside the lock so we merge onto whatever the previous update wrote.\n const existingIndex = (await this.indexClient.getIndex(indexName)) as any;\n const existingFieldNames = new Set((existingIndex.fields ?? []).map((field: any) => field.name));\n const missingFields = fields.filter(field => !existingFieldNames.has(field.name));\n\n if (missingFields.length === 0) {\n return;\n }\n\n await (this.indexClient as any).createOrUpdateIndex({\n ...existingIndex,\n fields: [...(existingIndex.fields ?? []), ...missingFields],\n });\n });\n this.schemaUpdateQueues.set(indexName, run);\n try {\n await run;\n } finally {\n if (this.schemaUpdateQueues.get(indexName) === run) {\n this.schemaUpdateQueues.delete(indexName);\n }\n }\n }\n\n /**\n * Adds a filterable field for every top-level scalar metadata key that the index\n * does not yet have, so that `filter: { key: value }` works without the caller\n * declaring the key up front. Mutates `fields` so the subsequent document build\n * writes the typed column. No-op when `autoIndexMetadata` is false.\n */\n private async ensureMetadataFields({\n indexName,\n metadataList,\n vectorFieldName,\n fields,\n }: {\n indexName: string;\n metadataList: Array<Record<string, any> | undefined>;\n vectorFieldName: string;\n fields: Map<string, IndexFieldCapabilities>;\n }): Promise<void> {\n if (!this.autoIndexMetadata) {\n return;\n }\n\n const missing = new Map<string, string>();\n for (const metadata of metadataList) {\n if (!metadata) continue;\n for (const [key, value] of Object.entries(metadata)) {\n if (fields.has(key) || missing.has(key)) continue;\n if (DEFAULT_DOCUMENT_FIELDS.has(key) || key === vectorFieldName) continue;\n // Names starting with \"azureSearch\" are reserved by the service.\n if (!AZURE_FIELD_NAME.test(key) || key.startsWith('azureSearch')) continue;\n const edmType = edmTypeForValue(value);\n if (!edmType) continue;\n missing.set(key, edmType);\n }\n }\n\n if (missing.size === 0) {\n return;\n }\n\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...missing].map(([name, type]) => ({\n name,\n type,\n searchable: false,\n filterable: true,\n retrievable: true,\n sortable: false,\n facetable: false,\n })),\n });\n\n // Another writer may have declared the field with a different type; re-read\n // the authoritative schema rather than trusting our inferred types.\n const refreshed = (await this.readIndexSchema(indexName)).fields;\n for (const [name, capability] of refreshed) {\n fields.set(name, capability);\n }\n }\n\n private buildDocumentFromMetadata({\n id,\n vector,\n vectorFieldName,\n metadata = {},\n fields,\n writeMetadata = true,\n }: {\n id: string;\n vector?: number[];\n vectorFieldName: string;\n metadata?: Record<string, any>;\n fields: Map<string, IndexFieldCapabilities>;\n writeMetadata?: boolean;\n }): Record<string, any> {\n const doc: Record<string, any> = { id };\n\n if (writeMetadata) {\n doc.metadata = JSON.stringify(metadata);\n }\n\n if (vector) {\n doc[vectorFieldName] = vector;\n }\n\n // `content` is derived from metadata, so whenever the metadata blob is\n // (re)written the column must follow it; otherwise a merge would keep a\n // stale value from the previous document.\n if (typeof metadata.content === 'string') {\n doc.content = metadata.content;\n } else if (writeMetadata) {\n doc.content = '';\n }\n\n for (const [fieldName, field] of fields.entries()) {\n if (DEFAULT_DOCUMENT_FIELDS.has(fieldName) || fieldName === vectorFieldName) {\n continue;\n }\n\n if (field.type === 'Collection(Edm.Single)') {\n continue;\n }\n\n // Only write the typed column when the JS value matches the column's Edm type.\n // Azure rejects the whole document otherwise (e.g. number into Edm.String:\n // \"Cannot convert the literal '0' to the expected type 'Edm.String'\"). The\n // JSON `metadata` blob remains the source of truth on read either way.\n if (Object.prototype.hasOwnProperty.call(metadata, fieldName)) {\n doc[fieldName] = valueMatchesEdmType(metadata[fieldName], field.type) ? metadata[fieldName] : null;\n }\n }\n\n return doc;\n }\n\n /**\n * Creates a new vector search index with the specified configuration\n *\n * @param params - Index creation parameters (supports both basic Mastra interface and Azure AI Search extended options)\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createIndex(params: CreateIndexParams | AzureAISearchCreateIndexParams): Promise<void> {\n const {\n indexName,\n dimension,\n metric = 'cosine',\n vectorField = 'vector',\n additionalFields = [],\n metadataIndexes = [],\n hnswParameters = {},\n semanticConfig,\n compression,\n } = params as AzureAISearchCreateIndexParams;\n\n if (!Number.isInteger(dimension) || dimension <= 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_INVALID_DIMENSION',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Dimension must be a positive integer',\n details: { indexName, dimension },\n });\n }\n\n try {\n const similarityFunction = METRIC_MAPPING[metric as keyof typeof METRIC_MAPPING];\n\n // Vector field configuration (customizable name).\n // Both `retrievable` and `hidden` are set: some API versions key retrievability\n // off `retrievable`, newer ones off `hidden` (inverted) — the service otherwise\n // silently defaults new vector fields to hidden/non-retrievable and `$select`ing\n // them for `includeVector` fails with \"'vector' is not a retrievable field\".\n const vectorFieldConfig = {\n name: vectorField,\n type: 'Collection(Edm.Single)',\n searchable: true,\n retrievable: true,\n hidden: false,\n vectorSearchDimensions: dimension,\n vectorSearchProfileName: 'vector-profile',\n };\n\n // Core default fields (aligned with other Mastra vector stores)\n const defaultFields = [\n {\n name: 'id',\n type: 'Edm.String',\n key: true,\n filterable: true,\n // Sortable so filter-based lookups can page past Azure's 100,000 $skip\n // ceiling using a stable ordered range scan (see findIdsByFilter).\n sortable: true,\n facetable: false,\n searchable: false,\n },\n vectorFieldConfig,\n {\n name: 'metadata',\n type: 'Edm.String',\n searchable: false,\n filterable: true,\n sortable: false,\n facetable: false,\n },\n {\n name: 'content',\n type: 'Edm.String',\n searchable: true,\n filterable: false,\n sortable: false,\n facetable: false,\n },\n ];\n\n // Merge default fields with additional fields (avoid duplicates)\n const existingFieldNames = new Set(defaultFields.map(f => f.name));\n const metadataIndexFields = this.getMetadataIndexFields(metadataIndexes, additionalFields);\n const allFields = [\n ...defaultFields,\n ...metadataIndexFields,\n ...additionalFields.filter(field => !existingFieldNames.has(field.name)),\n ];\n\n // HNSW parameters with customizable values\n const hnswConfig = {\n metric: similarityFunction,\n m: hnswParameters.m ?? 4,\n efConstruction: hnswParameters.efConstruction ?? 400,\n efSearch: hnswParameters.efSearch ?? 500,\n };\n\n const indexDefinition: any = {\n name: indexName,\n fields: allFields,\n vectorSearch: {\n profiles: [\n {\n name: 'vector-profile',\n algorithmConfigurationName: 'vector-algorithm',\n ...(compression && { compressionName: 'vector-compression' }),\n },\n ],\n algorithms: [\n {\n name: 'vector-algorithm',\n kind: 'hnsw',\n hnswParameters: hnswConfig,\n },\n ],\n ...(compression && {\n compressions: [\n {\n kind: compression.kind ?? 'scalarQuantization',\n compressionName: 'vector-compression',\n // Rescoring with full-precision vectors is what makes `oversampling`\n // meaningful: oversampling widens the initial (compressed) candidate\n // set so the rescore step has more to recover recall from.\n rescoringOptions: {\n enableRescoring: true,\n defaultOversampling: 10,\n },\n },\n ],\n }),\n },\n };\n\n // Add semantic search configuration if provided.\n // Note: the SDK's SearchIndex field is `semanticSearch`, not `semantic`, and its\n // SemanticField entries use `name`, not `fieldName` — an unrecognized top-level\n // property is silently dropped by the service rather than rejected, so a wrong\n // shape here does not surface as a createIndex error, only later as \"this index\n // must have valid semantic configurations defined\" from a semantic query.\n if (semanticConfig) {\n const prioritizedFields = semanticConfig.prioritizedFields ?? {\n titleField: { fieldName: 'content' },\n prioritizedContentFields: [{ fieldName: 'content' }],\n };\n indexDefinition.semanticSearch = {\n configurations: [\n {\n name: semanticConfig.name ?? 'default-semantic-config',\n prioritizedFields: {\n ...(prioritizedFields.titleField && {\n titleField: { name: prioritizedFields.titleField.fieldName },\n }),\n ...(prioritizedFields.prioritizedContentFields && {\n contentFields: prioritizedFields.prioritizedContentFields.map(f => ({ name: f.fieldName })),\n }),\n ...(prioritizedFields.prioritizedKeywordsFields && {\n keywordsFields: prioritizedFields.prioritizedKeywordsFields.map(f => ({ name: f.fieldName })),\n }),\n },\n },\n ],\n };\n }\n\n await this.indexClient.createIndex(indexDefinition as any);\n\n // Index created successfully\n } catch (error: any) {\n // Check if index already exists\n if (error?.statusCode === 409 || error?.message?.includes('already exists')) {\n await this.ensureExistingIndexFields({\n indexName,\n fields: [...this.getMetadataIndexFields(metadataIndexes, additionalFields), ...additionalFields],\n });\n // Index already exists, that's fine\n return;\n }\n\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_CREATE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, dimension, metric },\n },\n error,\n );\n }\n }\n\n /**\n * Creates an advanced vector search index with full Azure AI Search capabilities\n *\n * @param params - Extended Azure AI Search index creation parameters\n * @throws {MastraError} When index creation fails or invalid parameters are provided\n */\n async createAdvancedIndex(params: AzureAISearchCreateIndexParams): Promise<void> {\n return this.createIndex(params);\n }\n\n /**\n * Lists all available indexes in the Azure AI Search service\n *\n * @returns Array of index names\n * @throws {MastraError} When listing indexes fails\n */\n async listIndexes(): Promise<string[]> {\n try {\n const indexes = [];\n const indexIterator = this.indexClient.listIndexes();\n\n for await (const index of indexIterator) {\n indexes.push(index.name);\n }\n\n return indexes;\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_LIST_INDEXES_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n },\n error,\n );\n }\n }\n\n /**\n * Retrieves statistics and configuration information about an index\n *\n * @param indexName - Name of the index to describe\n * @returns Index statistics including dimension, count, and metric\n * @throws {MastraError} When describing index fails\n */\n async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {\n try {\n // Get index definition\n const index = await this.indexClient.getIndex(indexName);\n\n // Get document count\n const searchClient = this.getSearchClient(indexName);\n const countResult = await searchClient.getDocumentsCount();\n\n const { dimension } = this.schemaFromIndex(index);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n\n // Extract metric from vector search configuration\n let metric: 'cosine' | 'euclidean' | 'dotproduct' = 'cosine';\n if (index.vectorSearch?.algorithms) {\n const algorithm = index.vectorSearch.algorithms[0] as any;\n if (algorithm?.hnswParameters?.metric) {\n const azureMetric = algorithm.hnswParameters.metric;\n // Reverse lookup\n const metricEntry = Object.entries(METRIC_MAPPING).find(([_, value]) => value === azureMetric);\n if (metricEntry) {\n metric = metricEntry[0] as 'cosine' | 'euclidean' | 'dotproduct';\n }\n }\n }\n\n return { dimension, count: countResult, metric };\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DESCRIBE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes an index and all its documents\n *\n * @param indexName - Name of the index to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {\n try {\n await this.indexClient.deleteIndex(indexName);\n\n // Remove cached search client\n this.searchClients.delete(indexName);\n\n // Index deleted successfully\n } catch (error) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_INDEX_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName },\n },\n error,\n );\n }\n }\n\n /**\n * Inserts or updates vectors in the specified index\n *\n * @param indexName - Name of the index to upsert into\n * @param vectors - Array of vectors to upsert\n * @param metadata - Array of metadata objects corresponding to each vector\n * @param ids - Array of IDs corresponding to each vector (auto-generated if not provided)\n * @returns Array of IDs of the upserted vectors\n * @throws {MastraError} When upsert operation fails\n */\n async upsert({ indexName, vectors, metadata = [], ids, deleteFilter }: AzureAISearchUpsertParams): Promise<string[]> {\n if (!Array.isArray(vectors) || vectors.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_EMPTY_VECTORS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: 'Cannot upsert an empty vectors array',\n details: { indexName },\n });\n }\n if (metadata.length > 0 && metadata.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_METADATA_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and metadata must have the same length. Got ${vectors.length} vectors and ${metadata.length} metadata entries.`,\n details: { indexName, vectorsLength: vectors.length, metadataLength: metadata.length },\n });\n }\n if (ids && ids.length !== vectors.length) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_IDS_LENGTH_MISMATCH',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Vectors and ids must have the same length. Got ${vectors.length} vectors and ${ids.length} ids.`,\n details: { indexName, vectorsLength: vectors.length, idsLength: ids.length },\n });\n }\n\n try {\n if (deleteFilter) {\n await this.deleteVectors({ indexName, filter: deleteFilter });\n }\n\n // One schema read gives us the vector field, its dimension, and field types.\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions(vectors, dimension);\n await this.ensureMetadataFields({ indexName, metadataList: metadata, vectorFieldName, fields });\n\n // Generate IDs if not provided\n const vectorIds = ids || vectors.map(() => crypto.randomUUID());\n\n // Prepare documents for upload using dynamic vector field\n const documents = vectors.map((vector: number[], i: number) =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(vectorIds[i]!),\n vector,\n vectorFieldName,\n metadata: metadata[i] || {},\n fields,\n }),\n );\n\n // Upload documents (batched to respect Azure's per-request limits)\n const searchClient = this.getSearchClient(indexName);\n const uploadResults = await this.runBatchedIndexing(documents, batch =>\n searchClient.uploadDocuments(batch as any),\n );\n\n // Check for failures\n const failures = uploadResults.filter(result => !result.succeeded);\n if (failures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: uploadResults.length,\n failedCount: failures.length,\n firstFailedKey: failures[0]?.key || 'unknown',\n firstFailedError: failures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${failures.length} of ${uploadResults.length} documents failed to upload`),\n );\n }\n\n return vectorIds;\n } catch (error) {\n // If it's already a MastraError (e.g., from partial failure above), re-throw it\n if (error instanceof MastraError) {\n throw error;\n }\n\n // Normalize error to Error instance to avoid unsafe casting\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n\n // Otherwise, wrap the error in a MastraError\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPSERT_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, vectorCount: vectors?.length || 0 },\n },\n normalizedError,\n );\n }\n }\n\n /**\n * Standard MastraVector query method - compatible with Memory integration\n *\n * @param params - Standard query parameters compatible with MastraVector interface\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async query(params: QueryVectorParams<AzureAISearchVectorFilter>): Promise<QueryResult[]> {\n return this.advancedQuery(params);\n }\n\n /**\n * Advanced vector similarity search with full Azure AI Search capabilities\n *\n * @param indexName - Name of the index to search\n * @param queryVector - Vector to search with\n * @param topK - Maximum number of results to return\n * @param filter - Optional filter to apply to the search\n * @param includeVector - Whether to include the vector in each result (requires an extra retrievable select)\n * @param useSemanticSearch - Enable semantic search for better relevance\n * @param semanticOptions - Configuration for semantic search features\n * @param exhaustiveSearch - Use exhaustive k-NN search for exact results\n * @param oversampling - Oversampling factor for compressed vectors\n * @param weight - Relative weight for this vector query in hybrid scenarios\n * @param queryType - Query type: simple, full, or semantic\n * @param textVectorization - Enable automatic text vectorization\n * @param additionalVectorQueries - Multiple vector queries for hybrid search\n * @param filterMode - Apply filters before or after vector search\n * @returns Array of search results with scores and metadata\n * @throws {MastraError} When search operation fails\n */\n async advancedQuery({\n indexName,\n queryVector,\n filter,\n topK = 10,\n includeVector = false, // Kept for API compatibility but ignored due to Azure AI Search limitations\n useSemanticSearch = false,\n semanticOptions,\n exhaustiveSearch = false,\n oversampling,\n weight = 1.0,\n queryType = 'simple',\n textVectorization,\n additionalVectorQueries = [],\n filterMode = 'preFilter',\n }: AzureAISearchAdvancedQueryParams): Promise<QueryResult[]> {\n try {\n const searchClient = this.getSearchClient(indexName);\n\n // Detect vector field name\n const vectorFieldName = await this.getVectorFieldName(indexName);\n\n // Translate filter to OData syntax\n const odataFilter = this.transformFilter(filter);\n\n // Prepare primary vector query using dynamic field name\n const primaryVectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: queryVector as number[],\n kNearestNeighborsCount: topK,\n fields: [vectorFieldName],\n exhaustive: exhaustiveSearch,\n weight: weight,\n // Oversampling only makes sense for approximate (compressed) search — Azure\n // rejects the combination of oversampling and exhaustive search outright.\n ...(oversampling && !exhaustiveSearch && { oversampling }),\n };\n\n // Prepare additional vector queries for hybrid search\n const allVectorQueries: VectorQuery<any>[] = [primaryVectorQuery];\n\n // Add additional vector queries\n additionalVectorQueries.forEach(vq => {\n const vectorQuery: VectorizedQuery<any> = {\n kind: 'vector' as const,\n vector: vq.vector,\n kNearestNeighborsCount: vq.kNearestNeighborsCount || topK,\n fields: vq.fields || [vectorFieldName],\n weight: vq.weight || 1.0,\n exhaustive: exhaustiveSearch,\n };\n allVectorQueries.push(vectorQuery);\n });\n\n // Prepare vector search options\n const vectorSearchOptions: VectorSearchOptions<any> = {\n queries: allVectorQueries,\n filterMode: filterMode,\n };\n\n // Prepare field selection. The vector field is declared `retrievable: true`\n // in the index schema, so it can be selected back when explicitly requested.\n const selectFields = includeVector\n ? ['id', 'metadata', 'content', vectorFieldName]\n : ['id', 'metadata', 'content'];\n\n // Build search options\n let searchOptions: SearchRequestOptions<any> = {\n vectorSearchOptions,\n filter: odataFilter,\n top: topK,\n select: selectFields,\n // Combining a full-text `search` term with vectorSearchOptions makes Azure AI\n // Search run true hybrid search (BM25 + vector, fused via Reciprocal Rank Fusion)\n // in a single request. This needs no server-side vectorizer, unlike a\n // VectorizableTextQuery, which requires one to be configured on the index.\n ...(textVectorization?.fields && { searchFields: textVectorization.fields }),\n };\n\n // Add semantic search if enabled\n if (useSemanticSearch || queryType === 'semantic') {\n const semanticSearchOptions: SemanticSearchOptions = {\n configurationName: semanticOptions?.configurationName || 'default-semantic-config',\n ...(semanticOptions?.semanticQuery && { semanticQuery: semanticOptions.semanticQuery }),\n ...(semanticOptions?.answers && {\n answers: {\n answerType: 'extractive' as const,\n count: 3,\n threshold: 0.7,\n },\n }),\n ...(semanticOptions?.captions && {\n captions: {\n captionType: 'extractive' as const,\n highlight: true,\n },\n }),\n ...(semanticOptions?.maxWaitTime && { maxWaitInMilliseconds: semanticOptions.maxWaitTime }),\n };\n\n searchOptions = {\n ...searchOptions,\n queryType: 'semantic' as const,\n semanticSearchOptions,\n };\n } else {\n searchOptions = {\n ...searchOptions,\n queryType: queryType === 'full' ? ('full' as const) : ('simple' as const),\n };\n }\n\n // Perform search. A text query (from textVectorization.text) is passed as the\n // full-text search term rather than vectorized server-side, so hybrid search\n // works against any index without requiring a configured vectorizer.\n const searchResults = await searchClient.search(textVectorization?.text ?? '*', searchOptions as any);\n\n // Process results - Azure SDK returns object with .results property\n const results: QueryResult[] = [];\n for await (const result of searchResults.results) {\n if (result.document) {\n const queryResult: QueryResult = {\n id: decodeDocumentKey(result.document.id),\n score: result.score || 0,\n metadata: result.document.metadata\n ? (() => {\n try {\n return JSON.parse(result.document.metadata);\n } catch {\n return { _raw: result.document.metadata };\n }\n })()\n : {},\n document: result.document.content,\n ...(includeVector && { vector: (result.document as Record<string, any>)[vectorFieldName] }),\n };\n\n // Add semantic-specific fields if available\n if (result.rerankerScore) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.rerankerScore'] = result.rerankerScore;\n }\n if (result.captions && result.captions.length > 0) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.captions'] = result.captions;\n }\n if (result.highlights) {\n queryResult.metadata = queryResult.metadata || {};\n queryResult.metadata['@search.highlights'] = result.highlights;\n }\n\n results.push(queryResult);\n }\n }\n\n return results;\n } catch (error) {\n const unknownField = this.unknownFilterField(error);\n if (unknownField) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_FILTER_UNKNOWN_FIELD',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n text: `Filter references metadata field '${unknownField}' which does not exist on index '${indexName}'. Azure AI Search can only filter on declared fields: either upsert at least one document carrying '${unknownField}' as a string/number/boolean value (autoIndexMetadata), or declare it via createIndex({ metadataIndexes: ['${unknownField}'] }).`,\n details: { indexName, field: unknownField },\n },\n error,\n );\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_QUERY_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, topK },\n },\n error,\n );\n }\n }\n\n /**\n * Updates a vector and/or its metadata by ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to update\n * @param update - Object containing vector and/or metadata updates\n * @throws {MastraError} When update operation fails\n */\n async updateVector({ indexName, id, filter, update }: AzureAISearchUpdateParams): Promise<void> {\n try {\n if (!update.vector && !update.metadata) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_NO_UPDATES',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'No updates provided',\n });\n }\n\n if (!id && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_ID_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either id or filter must be provided',\n });\n }\n\n if (id && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_ID_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot provide both id and filter - they are mutually exclusive',\n });\n }\n\n const searchClient = this.getSearchClient(indexName);\n\n const { vectorFieldName, dimension, fields } = await this.readIndexSchema(indexName);\n\n // Validate vector dimension if updating vector\n if (update.vector) {\n if (dimension === undefined) {\n throw new Error('Vector field not found or missing dimensions');\n }\n this.validateVectorDimensions([update.vector], dimension);\n }\n\n let targetIds: string[];\n if (id) {\n targetIds = [id];\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot update with empty filter',\n });\n }\n targetIds = await this.findIdsByFilter(indexName, filter);\n }\n\n if (targetIds.length === 0) {\n return;\n }\n\n if (update.metadata) {\n await this.ensureMetadataFields({ indexName, metadataList: [update.metadata], vectorFieldName, fields });\n }\n\n const updatedDocs = targetIds.map(targetId =>\n this.buildDocumentFromMetadata({\n id: encodeDocumentKey(targetId),\n vector: update.vector,\n vectorFieldName,\n metadata: update.metadata,\n fields,\n writeMetadata: Boolean(update.metadata),\n }),\n );\n\n // Merge documents (update operation, batched to respect Azure's per-request limits)\n const mergeResults = await this.runBatchedIndexing(updatedDocs, batch =>\n searchClient.mergeDocuments(batch as any),\n );\n\n // Check for per-document failures\n const mergeFailures = mergeResults.filter(result => !result.succeeded);\n if (mergeFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: mergeResults.length,\n failedCount: mergeFailures.length,\n firstFailedKey: mergeFailures[0]?.key || 'unknown',\n firstFailedError: mergeFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${mergeFailures.length} of ${mergeResults.length} documents failed to update`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_UPDATE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, ...(id ? { id } : {}) },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes multiple vectors by IDs or metadata filter.\n */\n async deleteVectors({ indexName, ids, filter }: AzureAISearchDeleteVectorsParams): Promise<void> {\n try {\n if (ids && filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_IDS_AND_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot specify both ids and filter - they are mutually exclusive',\n });\n }\n\n if (!ids && !filter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_MISSING_IDS_OR_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Either filter or ids must be provided',\n });\n }\n\n let idsToDelete: string[];\n if (ids) {\n if (ids.length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_IDS',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty ids array',\n });\n }\n idsToDelete = ids;\n } else {\n if (!filter || Object.keys(filter).length === 0) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Cannot delete with empty filter',\n });\n }\n idsToDelete = await this.findIdsByFilter(indexName, filter);\n }\n\n if (idsToDelete.length === 0) {\n return;\n }\n\n const searchClient = this.getSearchClient(indexName);\n const deleteDocs = idsToDelete.map(id => ({ id: encodeDocumentKey(id) }));\n const deleteResults = await this.runBatchedIndexing(deleteDocs, batch =>\n searchClient.deleteDocuments(batch as any),\n );\n\n // Check for per-document failures\n const deleteFailures = deleteResults.filter(result => !result.succeeded);\n if (deleteFailures.length > 0) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n totalDocuments: deleteResults.length,\n failedCount: deleteFailures.length,\n firstFailedKey: deleteFailures[0]?.key || 'unknown',\n firstFailedError: deleteFailures[0]?.errorMessage || 'No error message',\n },\n },\n new Error(`${deleteFailures.length} of ${deleteResults.length} documents failed to delete`),\n );\n }\n } catch (error) {\n if (error instanceof MastraError) {\n throw error;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTORS_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n idsCount: ids?.length || 0,\n hasFilter: !!filter,\n },\n },\n error,\n );\n }\n }\n\n /**\n * Deletes a vector by its ID\n *\n * @param indexName - Name of the index containing the vector\n * @param id - ID of the vector to delete\n * @throws {MastraError} When deletion fails\n */\n async deleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {\n try {\n const searchClient = this.getSearchClient(indexName);\n const deleteResult = await searchClient.deleteDocuments([{ id: encodeDocumentKey(id) }] as any);\n const deleteFailure = deleteResult.results.find(result => !result.succeeded);\n\n if (deleteFailure) {\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_PARTIAL_FAILURE',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: {\n indexName,\n id,\n failedKey: deleteFailure.key || 'unknown',\n error: deleteFailure.errorMessage || 'No error message',\n },\n },\n new Error(`Document ${deleteFailure.key || id} failed to delete`),\n );\n }\n } catch (error: unknown) {\n if (error instanceof MastraError) {\n throw error;\n }\n // Don't throw error if document doesn't exist (404)\n if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 404) {\n return;\n }\n throw new MastraError(\n {\n id: 'STORAGE_AZURE_AI_SEARCH_DELETE_VECTOR_FAILED',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.THIRD_PARTY,\n details: { indexName, id },\n },\n error,\n );\n }\n }\n\n /**\n * Validates that all vectors have the correct dimension\n */\n private validateVectorDimensions(vectors: number[][], dimension: number): void {\n for (let i = 0; i < vectors.length; i++) {\n if (vectors[i]?.length !== dimension) {\n throw new Error(\n `Vector at index ${i} has invalid dimension ${vectors[i]?.length}. Expected ${dimension} dimensions.`,\n );\n }\n }\n }\n\n /**\n * Extracts the field name from Azure's \"Could not find a property named 'x'\" $filter error.\n */\n private unknownFilterField(error: unknown): string | undefined {\n const message = error instanceof Error ? error.message : String(error);\n return /Could not find a property named '([^']+)'/.exec(message)?.[1];\n }\n\n /**\n * Transforms filter to Azure AI Search OData syntax\n */\n private transformFilter(filter?: AzureAISearchVectorFilter): string | undefined {\n const translator = new AzureAISearchFilterTranslator();\n return translator.translate(filter);\n }\n\n /**\n * Finds document IDs matching a filter.\n */\n private async findIdsByFilter(indexName: string, filter: AzureAISearchVectorFilter): Promise<string[]> {\n const searchClient = this.getSearchClient(indexName);\n const odataFilter = this.transformFilter(filter);\n // Only update/delete call this. A filter that is non-empty as an object but\n // translates to no predicate (`{ $and: [] }`, `{ x: { $nin: [] } }`) would\n // otherwise select every document, which is never what a caller meant.\n if (!odataFilter) {\n throw new MastraError({\n id: 'STORAGE_AZURE_AI_SEARCH_EMPTY_FILTER',\n domain: ErrorDomain.STORAGE,\n category: ErrorCategory.USER,\n details: { indexName },\n text: 'Filter does not constrain any documents; refusing to apply it to every document',\n });\n }\n\n const ids: string[] = [];\n const pageSize = 1000;\n // Azure AI Search caps $skip at 100,000, so paginate with a stable\n // ordered range scan (\"search after\") on the sortable key field instead.\n let lastId: string | undefined;\n\n while (true) {\n const rangeClause = lastId !== undefined ? `id gt '${lastId.replace(/'/g, \"''\")}'` : undefined;\n const combinedFilter = [odataFilter ? `(${odataFilter})` : undefined, rangeClause].filter(Boolean).join(' and ');\n\n const searchResults = await searchClient.search('*', {\n filter: combinedFilter || undefined,\n top: pageSize,\n orderBy: ['id asc'],\n select: ['id'],\n } as any);\n\n let count = 0;\n for await (const result of searchResults.results) {\n if (result.document?.id) {\n ids.push(decodeDocumentKey(result.document.id));\n // Range-scan cursor must stay in stored (encoded) key space.\n lastId = result.document.id;\n }\n count++;\n }\n\n if (count < pageSize) {\n break;\n }\n }\n\n return ids;\n }\n\n /**\n * Convenience method for semantic search\n *\n * @param params - Query parameters with semantic search enabled\n * @returns Array of search results with semantic enhancements\n */\n async semanticQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'useSemanticSearch' | 'queryType' | 'semanticOptions'> & {\n semanticConfig?: string;\n semanticQuery?: string;\n enableAnswers?: boolean;\n enableCaptions?: boolean;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n useSemanticSearch: true,\n queryType: 'semantic',\n semanticOptions: {\n configurationName: params.semanticConfig,\n semanticQuery: params.semanticQuery,\n answers: params.enableAnswers,\n captions: params.enableCaptions,\n },\n });\n }\n\n /**\n * Convenience method for hybrid vector + text search. Combines the vector query with a\n * BM25 full-text query over `textQuery`, fused via Azure AI Search's native Reciprocal\n * Rank Fusion. No vectorizer needs to be configured on the index.\n *\n * @param params - Query parameters with a text query\n * @returns Array of search results from hybrid search\n */\n async hybridQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'textVectorization'> & {\n textQuery: string;\n /** Searchable text fields to match `textQuery` against. Defaults to the index's default searchable fields. */\n vectorFields?: string[];\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n textVectorization: {\n text: params.textQuery,\n fields: params.vectorFields,\n },\n });\n }\n\n /**\n * Convenience method for multi-vector search\n *\n * @param params - Query parameters with multiple vectors\n * @returns Array of search results from multi-vector search\n */\n async multiVectorQuery(\n params: Omit<AzureAISearchAdvancedQueryParams, 'additionalVectorQueries'> & {\n vectors: Array<{\n vector: number[];\n weight?: number;\n fields?: string[];\n }>;\n },\n ): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n additionalVectorQueries: params.vectors.map(v => ({\n vector: v.vector,\n weight: v.weight,\n fields: v.fields,\n kNearestNeighborsCount: params.topK,\n })),\n });\n }\n\n /**\n * Convenience method for exhaustive (exact) search\n *\n * @param params - Query parameters with exhaustive search enabled\n * @returns Array of search results from exhaustive search\n */\n async exactQuery(params: Omit<AzureAISearchAdvancedQueryParams, 'exhaustiveSearch'>): Promise<QueryResult[]> {\n return this.advancedQuery({\n ...params,\n exhaustiveSearch: true,\n });\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/azure-ai-search",
3
- "version": "0.1.1",
3
+ "version": "0.1.2-alpha.1",
4
4
  "description": "Azure AI Search vector store provider for Mastra",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,22 +20,22 @@
20
20
  },
21
21
  "license": "Apache-2.0",
22
22
  "dependencies": {
23
- "@azure/core-auth": "^1.7.2",
24
- "@azure/search-documents": "^12.0.0"
23
+ "@azure/core-auth": "^1.11.0",
24
+ "@azure/search-documents": "^12.2.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@types/node": "22.20.1",
28
- "@vitest/coverage-v8": "4.1.11",
29
- "@vitest/ui": "4.1.11",
30
- "dotenv": "^17.2.3",
31
- "tsdown": "0.22.9",
32
- "tsx": "^4.23.1",
27
+ "@types/node": "22.19.15",
28
+ "@vitest/coverage-v8": "4.1.12",
29
+ "@vitest/ui": "4.1.12",
30
+ "dotenv": "^17.4.2",
31
+ "tsdown": "0.23.1",
32
+ "tsx": "^4.23.15",
33
33
  "typescript": "^7.0.2",
34
- "vitest": "4.1.11",
35
- "@internal/lint": "0.0.145",
34
+ "vitest": "4.1.12",
36
35
  "@internal/storage-test-utils": "0.0.141",
37
36
  "@internal/types-builder": "0.0.120",
38
- "@mastra/core": "1.79.0"
37
+ "@internal/lint": "0.0.145",
38
+ "@mastra/core": "1.80.0-alpha.4"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@mastra/core": ">=1.0.0-0 <2.0.0-0"