From aac1f4d201ff8e1ea61f1f11024dd0f0dbf1be52 Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 12:58:02 +0100 Subject: [PATCH 1/7] Make changes to fix reported bugs and to close the following issues: - https://github.com/weaviate/typescript-client/issues/325 - https://github.com/weaviate/typescript-client/issues/328 - https://github.com/weaviate/typescript-client/issues/345 - https://github.com/weaviate/typescript-client/issues/346 - https://github.com/weaviate/typescript-client/issues/349 - https://github.com/weaviate/typescript-client/issues/350 - https://github.com/weaviate/typescript-client/issues/350 --- src/collections/config/integration.test.ts | 22 ++++ src/collections/config/types/generative.ts | 1 + src/collections/config/types/vectorizer.ts | 45 ++++++++ src/collections/configure/types/vectorizer.ts | 103 ++++++++---------- src/collections/configure/unit.test.ts | 79 ++++++++++++++ src/collections/configure/vectorizer.ts | 41 +++++++ src/openapi/schema.ts | 24 +++- src/roles/index.ts | 42 ++++++- src/roles/integration.test.ts | 24 ++++ src/roles/types.ts | 12 ++ src/roles/util.ts | 31 ++++++ 11 files changed, 361 insertions(+), 63 deletions(-) diff --git a/src/collections/config/integration.test.ts b/src/collections/config/integration.test.ts index c77d4fd6..119d1594 100644 --- a/src/collections/config/integration.test.ts +++ b/src/collections/config/integration.test.ts @@ -8,6 +8,7 @@ import { ModuleConfig, MultiTenancyConfig, PropertyConfig, + RQConfig, RerankerCohereConfig, VectorIndexConfigDynamic, VectorIndexConfigHNSW, @@ -877,4 +878,25 @@ describe('Testing of the collection.config namespace', () => { ); }); }); + + requireAtLeast(1, 32, 0).it( + 'should be able to create a collection with RQ quantizer bits option', + async () => { + const collectionName = 'TestCollectionRQQuantizerBits'; + const collection = await client.collections.create({ + name: collectionName, + vectorizers: weaviate.configure.vectors.selfProvided({ + quantizer: weaviate.configure.vectorIndex.quantizer.rq({ bits: 1, rescoreLimit: 10 }), + }), + }); + await collection.config.get().then((config) => { + console.log(JSON.stringify(config, null, 2)); + const indexConfig = config.vectorizers.default.indexConfig as VectorIndexConfigHNSW; + expect(indexConfig.quantizer).toBeDefined(); + expect(indexConfig.quantizer?.type).toEqual('rq'); + expect((indexConfig.quantizer as RQConfig).bits).toEqual(1); + expect((indexConfig.quantizer as RQConfig).rescoreLimit).toEqual(10); + }); + } + ); }); diff --git a/src/collections/config/types/generative.ts b/src/collections/config/types/generative.ts index 41bfea2a..239009e6 100644 --- a/src/collections/config/types/generative.ts +++ b/src/collections/config/types/generative.ts @@ -12,6 +12,7 @@ export type GenerativeAWSConfig = { service: string; model?: string; endpoint?: string; + maxTokens?: number; }; export type GenerativeAnthropicConfig = { diff --git a/src/collections/config/types/vectorizer.ts b/src/collections/config/types/vectorizer.ts index ef0c940c..ed75f606 100644 --- a/src/collections/config/types/vectorizer.ts +++ b/src/collections/config/types/vectorizer.ts @@ -40,10 +40,12 @@ export type Vectorizer = | 'text2vec-nvidia' | 'text2vec-mistral' | 'text2vec-model2vec' + | 'text2vec-morph' | 'text2vec-ollama' | 'text2vec-openai' | Text2VecPalmVectorizer | 'text2vec-google' + | 'text2vec-google-ai-studio' | 'text2vec-transformers' | 'text2vec-voyageai' | 'text2vec-weaviate' @@ -93,6 +95,30 @@ export type Multi2VecNvidiaConfig = { }; }; +/** The configuration for multi-media vectorization using the AWS module. + * + * See the [documentation](https://weaviate.io/developers/weaviate/model-providers/aws/embeddings-multimodal) for detailed usage. + */ +export type Multi2VecAWSConfig = { + /** The dimensionality of the vector once embedded. */ + dimensions?: number; + /** The model to use. */ + model?: string; + /** The AWS region where the model runs. */ + region?: string; + /** The image fields used when vectorizing. */ + imageFields?: string[]; + /** The text fields used when vectorizing. */ + textFields?: string[]; + /** The weights of the fields used for vectorization. */ + weights?: { + /** The weights of the image fields. */ + imageFields?: number[]; + /** The weights of the text fields. */ + textFields?: number[]; + }; +}; + /** The configuration for multi-media vectorization using the CLIP module. * * See the [documentation](https://weaviate.io/developers/weaviate/model-providers/transformers/embeddings-multimodal) for detailed usage. @@ -504,6 +530,8 @@ export type Text2VecPalmConfig = Text2VecGoogleConfig; export type Text2VecGoogleConfig = { /** The API endpoint to use without a leading scheme such as `http://`. */ apiEndpoint?: string; + /** The dimensionality of the vector once embedded. */ + dimensions?: number; /** The model ID to use. */ model?: string; /** The model ID to use. @@ -517,6 +545,13 @@ export type Text2VecGoogleConfig = { vectorizeCollectionName?: boolean; }; +export type Text2VecGoogleAiStudioConfig = { + /** The model ID to use. */ + model?: string; + /** The Weaviate property name for the `gecko-002` or `gecko-003` model to use as the title. */ + titleProperty?: string; +}; + /** * The configuration for text vectorization using the Transformers module. * @@ -579,10 +614,18 @@ export type Text2VecModel2Vec = { vectorizeCollectionName?: boolean; }; +export type Text2VecMorphConfig = { + /** The base URL to use where API requests should go. */ + baseURL?: string; + /** The model to use. */ + model?: string; +}; + export type NoVectorizerConfig = {}; export type VectorizerConfig = | Img2VecNeuralConfig + | Multi2VecAWSConfig | Multi2VecClipConfig | Multi2VecBindConfig | Multi2VecGoogleConfig @@ -652,6 +695,8 @@ export type VectorizerConfigType = V extends 'img2vec-neural' ? Text2VecMistralConfig | undefined : V extends 'text2vec-model2vec' ? Text2VecModel2Vec | undefined + : V extends 'text2vec-morph' + ? Text2VecMorphConfig | undefined : V extends 'text2vec-ollama' ? Text2VecOllamaConfig | undefined : V extends 'text2vec-openai' diff --git a/src/collections/configure/types/vectorizer.ts b/src/collections/configure/types/vectorizer.ts index 0bc6e6eb..a0d776a7 100644 --- a/src/collections/configure/types/vectorizer.ts +++ b/src/collections/configure/types/vectorizer.ts @@ -1,7 +1,16 @@ import { Img2VecNeuralConfig, ModuleConfig, + Multi2MultivecJinaAIConfig, + Multi2VecAWSConfig, + Multi2VecBindConfig, + Multi2VecClipConfig, + Multi2VecCohereConfig, Multi2VecField, + Multi2VecGoogleConfig, + Multi2VecJinaAIConfig, + Multi2VecNvidiaConfig, + Multi2VecVoyageAIConfig, Ref2VecCentroidConfig, Text2MultiVecJinaAIConfig, Text2VecAWSConfig, @@ -10,11 +19,13 @@ import { Text2VecContextionaryConfig, Text2VecDatabricksConfig, Text2VecGPT4AllConfig, + Text2VecGoogleAiStudioConfig, Text2VecGoogleConfig, Text2VecHuggingFaceConfig, Text2VecJinaAIConfig, Text2VecMistralConfig, Text2VecModel2Vec, + Text2VecMorphConfig, Text2VecNvidiaConfig, Text2VecOllamaConfig, Text2VecOpenAIConfig, @@ -128,16 +139,27 @@ export type Img2VecNeuralConfigCreate = Img2VecNeuralConfig; // image_fields: The image fields to use in vectorization. // text_fields: The text fields to use in vectorization. +type Multi2VecOmissions = + | 'audioFields' + | 'depthFields' + | 'imageFields' + | 'IMUFields' + | 'thermalFields' + | 'textFields' + | 'videoFields' + | 'weights'; + /** The configuration for the `multi2vec-nvidia` vectorizer. */ -export type Multi2VecNvidiaConfigCreate = { - /** The model to use. Defaults to `None`, which uses the server-defined default. */ - model?: string; - /** The base URL where API requests should go. */ - baseURL?: string; - /** Whether to apply truncation. */ - truncation?: boolean; +export type Multi2VecNvidiaConfigCreate = Omit & { + /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ + imageFields?: string[] | Multi2VecField[]; /** Format in which the embeddings are encoded. Defaults to `None`, so the embeddings are represented as a list of floating-point numbers. */ outputEncoding?: string; + /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ + textFields?: string[] | Multi2VecField[]; +}; + +export type Multi2VecAWSConfigCreate = Omit & { /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ imageFields?: string[] | Multi2VecField[]; /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ @@ -145,19 +167,15 @@ export type Multi2VecNvidiaConfigCreate = { }; /** The configuration for the `multi2vec-clip` vectorizer. */ -export type Multi2VecClipConfigCreate = { +export type Multi2VecClipConfigCreate = Omit & { /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ imageFields?: string[] | Multi2VecField[]; - /** The inference url to use where API requests should go. */ - inferenceUrl?: string; /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ textFields?: string[] | Multi2VecField[]; - /** Whether to vectorize the collection name. */ - vectorizeCollectionName?: boolean; }; /** The configuration for the `multi2vec-bind` vectorizer. */ -export type Multi2VecBindConfigCreate = { +export type Multi2VecBindConfigCreate = Omit & { /** The audio fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ audioFields?: string[] | Multi2VecField[]; /** The depth fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ @@ -172,84 +190,43 @@ export type Multi2VecBindConfigCreate = { thermalFields?: string[] | Multi2VecField[]; /** The video fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ videoFields?: string[] | Multi2VecField[]; - /** Whether to vectorize the collection name. */ - vectorizeCollectionName?: boolean; }; /** The configuration for the `multi2vec-cohere` vectorizer. */ -export type Multi2VecCohereConfigCreate = { - /** The base URL to use where API requests should go. */ - baseURL?: string; +export type Multi2VecCohereConfigCreate = Omit & { /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ imageFields?: string[] | Multi2VecField[]; - /** The specific model to use. */ - model?: string; /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ textFields?: string[] | Multi2VecField[]; - /** The truncation strategy to use. */ - truncate?: string; - /** Whether to vectorize the collection name. */ - vectorizeCollectionName?: boolean; }; -export type Multi2MultivecJinaAIConfigCreate = { - /** The image fields to use in vectorization. */ - imageFields?: string[]; - /** The text fields to use in vectorization. */ - textFields?: string[]; -}; +export type Multi2MultivecJinaAIConfigCreate = Multi2MultivecJinaAIConfig; -export type Multi2VecJinaAIConfigCreate = { - /** The base URL to use where API requests should go. */ - baseURL?: string; - /** The dimensionality of the vector once embedded. */ - dimensions?: number; - /** The model to use. */ - model?: string; +export type Multi2VecJinaAIConfigCreate = Omit & { /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ imageFields?: string[] | Multi2VecField[]; /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ textFields?: string[] | Multi2VecField[]; - /** Whether to vectorize the collection name. */ - vectorizeCollectionName?: boolean; }; /** @deprecated Use `Multi2VecGoogleConfigCreate` instead.*/ export type Multi2VecPalmConfigCreate = Multi2VecGoogleConfigCreate; /** The configuration for the `multi2vec-google` vectorizer. */ -export type Multi2VecGoogleConfigCreate = { - /** The project id of the model in GCP. */ - projectId: string; - /** Where the model runs */ - location: string; +export type Multi2VecGoogleConfigCreate = Omit & { /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ imageFields?: string[] | Multi2VecField[]; /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ textFields?: string[] | Multi2VecField[]; /** The video fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ videoFields?: string[] | Multi2VecField[]; - /** The model ID to use. */ - modelId?: string; - /** The dimensionality of the vector once embedded. */ - dimensions?: number; - /** Whether to vectorize the collection name. */ - vectorizeCollectionName?: boolean; }; -export type Multi2VecVoyageAIConfigCreate = { - /** The base URL to use where API requests should go. */ - baseURL?: string; +export type Multi2VecVoyageAIConfigCreate = Omit & { /** The image fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ imageFields?: string[] | Multi2VecField[]; - /** The model to use. */ - model?: string; /** The text fields to use in vectorization. Can be string of `Multi2VecField` type. If string, weight 0 will be assumed. */ textFields?: string[] | Multi2VecField[]; - /** Whether the input should be truncated to fit the context window. */ - truncate?: boolean; - /** Whether to vectorize the collection name. */ - vectorizeCollectionName?: boolean; }; export type Ref2VecCentroidConfigCreate = Ref2VecCentroidConfig; @@ -276,6 +253,8 @@ export type Text2VecMistralConfigCreate = Text2VecMistralConfig; export type Text2VecModel2VecConfigCreate = Text2VecModel2Vec; +export type Text2VecMorphConfigCreate = Text2VecMorphConfig; + export type Text2VecOllamaConfigCreate = Text2VecOllamaConfig; export type Text2VecOpenAIConfigCreate = Text2VecOpenAIConfig; @@ -285,6 +264,8 @@ export type Text2VecPalmConfigCreate = Text2VecGoogleConfig; export type Text2VecGoogleConfigCreate = Text2VecGoogleConfig; +export type Text2VecGoogleAiStudioConfigCreate = Text2VecGoogleAiStudioConfig; + export type Text2VecTransformersConfigCreate = Text2VecTransformersConfig; export type Text2VecVoyageAIConfigCreate = Text2VecVoyageAIConfig; @@ -335,6 +316,8 @@ export type VectorizerConfigCreateType = V extends 'img2vec-neural' ? Text2VecMistralConfigCreate | undefined : V extends 'text2vec-model2vec' ? Text2VecModel2VecConfigCreate | undefined + : V extends 'text2vec-morph' + ? Text2VecMorphConfigCreate | undefined : V extends 'text2vec-ollama' ? Text2VecOllamaConfigCreate | undefined : V extends 'text2vec-openai' @@ -345,6 +328,8 @@ export type VectorizerConfigCreateType = V extends 'img2vec-neural' ? Text2VecPalmConfigCreate | undefined : V extends 'text2vec-google' ? Text2VecGoogleConfigCreate | undefined + : V extends 'text2vec-google-ai-studio' + ? Text2VecGoogleAiStudioConfigCreate | undefined : V extends 'text2vec-transformers' ? Text2VecTransformersConfigCreate | undefined : V extends 'text2vec-voyageai' diff --git a/src/collections/configure/unit.test.ts b/src/collections/configure/unit.test.ts index e7e61292..30ec320d 100644 --- a/src/collections/configure/unit.test.ts +++ b/src/collections/configure/unit.test.ts @@ -1405,6 +1405,46 @@ describe('Unit testing of the vectorizer factory class', () => { }); }); + it('should create the correct Text2VecGoogleAiStudioConfig type with defaults', () => { + const config = configure.vectors.text2VecGoogleAiStudio(); + expect(config).toEqual>({ + name: undefined, + vectorIndex: { + name: 'hnsw', + config: undefined, + }, + vectorizer: { + name: 'text2vec-google', + config: { + apiEndpoint: 'generativelanguage.googleapis.com', + }, + }, + }); + }); + + it('should create the correct Text2VecGoogleAiStudioConfig type with all values', () => { + const config = configure.vectors.text2VecGoogleAiStudio({ + name: 'test', + model: 'model-id', + titleProperty: 'title', + }); + expect(config).toEqual>({ + name: 'test', + vectorIndex: { + name: 'hnsw', + config: undefined, + }, + vectorizer: { + name: 'text2vec-google', + config: { + apiEndpoint: 'generativelanguage.googleapis.com', + model: 'model-id', + titleProperty: 'title', + }, + }, + }); + }); + it('should create the correct Text2VecPalmConfig type using deprecated method with defaults', () => { const config = configure.vectorizer.text2VecPalm(); expect(config).toEqual>({ @@ -1612,6 +1652,43 @@ describe('Unit testing of the vectorizer factory class', () => { }, }); }); + + it('should create the correct Text2VecMorphConfig type with defaults', () => { + const config = configure.vectors.text2VecMorph(); + expect(config).toEqual>({ + name: undefined, + vectorIndex: { + name: 'hnsw', + config: undefined, + }, + vectorizer: { + name: 'text2vec-morph', + config: undefined, + }, + }); + }); + + it('should create the correct Text2VecMorphConfig type with all values', () => { + const config = configure.vectors.text2VecMorph({ + name: 'test', + baseURL: 'base-url', + model: 'model', + }); + expect(config).toEqual>({ + name: 'test', + vectorIndex: { + name: 'hnsw', + config: undefined, + }, + vectorizer: { + name: 'text2vec-morph', + config: { + baseURL: 'base-url', + model: 'model', + }, + }, + }); + }); }); describe('Unit testing of the multiVectors factory class', () => { @@ -1792,6 +1869,7 @@ describe('Unit testing of the generative factory class', () => { model: 'model', region: 'region', service: 'service', + maxTokens: 100, }); expect(config).toEqual>({ name: 'generative-aws', @@ -1800,6 +1878,7 @@ describe('Unit testing of the generative factory class', () => { model: 'model', region: 'region', service: 'service', + maxTokens: 100, }, }); }); diff --git a/src/collections/configure/vectorizer.ts b/src/collections/configure/vectorizer.ts index c739d218..e9c863cf 100644 --- a/src/collections/configure/vectorizer.ts +++ b/src/collections/configure/vectorizer.ts @@ -844,6 +844,7 @@ const __vectors_shaded = { text2VecWeaviate: ( opts?: Omit, 'vectorizeCollectionName'> ) => legacyVectors.text2VecWeaviate(opts), + /** @deprecated The contextionary model is old and not recommended for use. If you are looking for a local, lightweight model try the new text2vec-model2vec module instead. */ text2VecContextionary: ( opts?: Omit, 'vectorizeCollectionName'> ) => legacyVectors.text2VecContextionary(opts), @@ -885,6 +886,7 @@ const __vectors_shaded = { text2VecHuggingFace: ( opts?: Omit, 'vectorizeCollectionName'> ) => legacyVectors.text2VecHuggingFace(opts), + /** @deprecated The `text2vec-gpt4all` vectorizer is deprecated and will be removed in a future release. See the docs (https://docs.weaviate.io/weaviate/model-providers) for alternatives. */ text2VecGPT4All: ( opts?: Omit, 'vectorizeCollectionName'> ) => legacyVectors.text2VecGPT4All(opts), @@ -967,6 +969,45 @@ export const vectors = (({ text2VecPalm, multi2VecPalm, ...rest }) => ({ }, }); }, + /** + * Create a `VectorConfigCreate` object with the vectorizer set to `'text2vec-google'` with specific options for AI studio deployments. + * + * See the [documentation](https://weaviate.io/developers/weaviate/model-providers/google/embeddings) for detailed usage. + * + * @param {ConfigureTextVectorizerOptions} [opts] The configuration for the `text2vec-google` vectorizer. + * @returns {VectorConfigCreate, N, I, 'text2vec-google'>} The configuration object. + */ + text2VecGoogleAiStudio: ( + opts?: ConfigureTextVectorizerOptions + ): VectorConfigCreate, N, I, 'text2vec-google'> => { + const { name, sourceProperties, quantizer, vectorIndexConfig, ...config } = opts || {}; + return makeVectorizer(name, { + quantizer, + sourceProperties, + vectorIndexConfig, + vectorizerConfig: { + name: 'text2vec-google', + config: { + apiEndpoint: 'generativelanguage.googleapis.com', + ...config, + }, + }, + }); + }, + text2VecMorph: ( + opts?: ConfigureTextVectorizerOptions + ): VectorConfigCreate, N, I, 'text2vec-morph'> => { + const { name, quantizer, sourceProperties, vectorIndexConfig, ...config } = opts || {}; + return makeVectorizer(name, { + quantizer, + sourceProperties, + vectorIndexConfig, + vectorizerConfig: { + name: 'text2vec-morph', + config: Object.keys(config).length === 0 ? undefined : config, + }, + }); + }, }))(legacyVectors); export const multiVectors = { diff --git a/src/openapi/schema.ts b/src/openapi/schema.ts index c2cfab1c..25837d89 100644 --- a/src/openapi/schema.ts +++ b/src/openapi/schema.ts @@ -267,7 +267,7 @@ export interface paths { delete: operations['aliases.delete']; }; '/backups/{backend}': { - /** [Coming soon] List all backups in progress not implemented yet. */ + /** List all created backups IDs, Status */ get: operations['backups.list']; /** Start creating a backup for a set of collections.

Notes:
- Weaviate uses gzip compression by default.
- Weaviate stays usable while a backup process is ongoing. */ post: operations['backups.create']; @@ -1094,6 +1094,16 @@ export interface definitions { * @enum {string} */ status?: 'STARTED' | 'TRANSFERRING' | 'TRANSFERRED' | 'SUCCESS' | 'FAILED' | 'CANCELED'; + /** + * Format: date-time + * @description Timestamp when the backup process started + */ + startedAt?: string; + /** + * Format: date-time + * @description Timestamp when the backup process completed (successfully or with failure) + */ + completedAt?: string; }; /** @description The definition of a backup restore metadata */ BackupRestoreStatusResponse: { @@ -1206,6 +1216,16 @@ export interface definitions { * @enum {string} */ status?: 'STARTED' | 'TRANSFERRING' | 'TRANSFERRED' | 'SUCCESS' | 'FAILED' | 'CANCELED'; + /** + * Format: date-time + * @description Timestamp when the backup process started + */ + startedAt?: string; + /** + * Format: date-time + * @description Timestamp when the backup process completed (successfully or with failure) + */ + completedAt?: string; }[]; /** @description Request body for restoring a backup for a set of classes */ BackupRestoreRequest: { @@ -4697,7 +4717,7 @@ export interface operations { }; }; }; - /** [Coming soon] List all backups in progress not implemented yet. */ + /** List all created backups IDs, Status */ 'backups.list': { parameters: { path: { diff --git a/src/roles/index.ts b/src/roles/index.ts index 6760040f..a10ed804 100644 --- a/src/roles/index.ts +++ b/src/roles/index.ts @@ -17,6 +17,7 @@ import { NodesPermission, Permission, PermissionsInput, + ReplicatePermission, Role, RolesPermission, TenantsPermission, @@ -71,10 +72,10 @@ export interface Roles { * Create a new role. * * @param {string} roleName The name of the new role. - * @param {PermissionsInput} permissions The permissions to assign to the new role. + * @param {PermissionsInput} [permissions] The permissions to assign to the new role. * @returns {Promise} The newly created role. */ - create: (roleName: string, permissions: PermissionsInput) => Promise; + create: (roleName: string, permissions?: PermissionsInput) => Promise; /** * Check if a role exists. * @@ -369,6 +370,43 @@ export const permissions = { }); }, }, + /** + * Create a set of permissions specific to shard replica movement operations. + * + * For all collections, provide the `collection` argument as `'*'`. + * For all shards, provide the `shard` argument as `'*'`. + * + * Providing arrays of collections and shards will create permissions for each combination of collection and shard. + * E.g., `replicate({ collection: ['A', 'B'], shard: ['X', 'Y'] })` will create permissions for shards `X` and `Y` in both collections `A` and `B`. + * + * @param {string | string[]} args.collection The collection or collections to create permissions for. + * @param {string | string[]} args.shard The shard or shards to create permissions for. + * @param {boolean} [args.create] Whether to allow creating replicas. Defaults to `false`. + * @param {boolean} [args.read] Whether to allow reading replicas. Defaults to `false`. + * @param {boolean} [args.update] Whether to allow updating replicas. Defaults to `false`. + * @param {boolean} [args.delete] Whether to allow deleting replicas. Defaults to `false`. + * @returns {ReplicatePermission[]} The permissions for the specified collections and shards. + */ + replicate: (args: { + collection: string | string[]; + shard: string | string[]; + create?: boolean; + read?: boolean; + update?: boolean; + delete?: boolean; + }): ReplicatePermission[] => { + const collections = Array.isArray(args.collection) ? args.collection : [args.collection]; + const shards = Array.isArray(args.shard) ? args.shard : [args.shard]; + const combinations = collections.flatMap((collection) => shards.map((shard) => ({ collection, shard }))); + return combinations.map(({ collection, shard }) => { + const out: ReplicatePermission = { collection, shard, actions: [] }; + if (args.create) out.actions.push('create_replicate'); + if (args.read) out.actions.push('read_replicate'); + if (args.update) out.actions.push('update_replicate'); + if (args.delete) out.actions.push('delete_replicate'); + return out; + }); + }, /** * Create a set of permissions specific to any operations involving roles. * diff --git a/src/roles/integration.test.ts b/src/roles/integration.test.ts index ccddcf82..7a723794 100644 --- a/src/roles/integration.test.ts +++ b/src/roles/integration.test.ts @@ -27,6 +27,7 @@ const emptyPermissions = { dataPermissions: [], groupsPermissions: [], nodesPermissions: [], + replicatePermissions: [], rolesPermissions: [], tenantsPermissions: [], usersPermissions: [], @@ -314,6 +315,29 @@ const testCases: TestCase[] = [ ], }, }, + { + roleName: 'replicate', + requireVersion: [1, 32, 0], + permissions: weaviate.permissions.replicate({ + collection: 'SomeCollection', + shard: 'shard1', + create: true, + read: true, + update: true, + delete: true, + }), + expected: { + name: 'replicate', + ...emptyPermissions, + replicatePermissions: [ + { + collection: 'SomeCollection', + shard: 'shard1', + actions: ['create_replicate', 'read_replicate', 'update_replicate', 'delete_replicate'], + }, + ], + }, + }, ]; requireAtLeast(1, 29, 0).describe('Integration testing of the roles namespace', () => { diff --git a/src/roles/types.ts b/src/roles/types.ts index 2a757fe3..061f8505 100644 --- a/src/roles/types.ts +++ b/src/roles/types.ts @@ -20,6 +20,10 @@ export type DataAction = Extract< >; export type GroupsAction = Extract; export type NodesAction = Extract; +export type ReplicateAction = Extract< + Action, + 'create_replicate' | 'read_replicate' | 'update_replicate' | 'delete_replicate' +>; export type RolesAction = Extract; export type TenantsAction = Extract< Action, @@ -75,6 +79,12 @@ export type NodesPermission = { actions: NodesAction[]; }; +export type ReplicatePermission = { + collection: string; + shard: string; + actions: ReplicateAction[]; +}; + export type RolesPermission = { role: string; actions: RolesAction[]; @@ -100,6 +110,7 @@ export type Role = { dataPermissions: DataPermission[]; groupsPermissions: GroupsPermission[]; nodesPermissions: NodesPermission[]; + replicatePermissions: ReplicatePermission[]; rolesPermissions: RolesPermission[]; tenantsPermissions: TenantsPermission[]; usersPermissions: UsersPermission[]; @@ -113,6 +124,7 @@ export type Permission = | DataPermission | GroupsPermission | NodesPermission + | ReplicatePermission | RolesPermission | TenantsPermission | UsersPermission; diff --git a/src/roles/util.ts b/src/roles/util.ts index d1607e12..5484196a 100644 --- a/src/roles/util.ts +++ b/src/roles/util.ts @@ -25,6 +25,8 @@ import { NodesPermission, Permission, PermissionsInput, + ReplicateAction, + ReplicatePermission, Role, RolesAction, RolesPermission, @@ -73,6 +75,14 @@ export class PermissionGuards { PermissionGuards.includes(permission, 'read_groups', 'assign_and_revoke_groups'); static isNodes = (permission: Permission): permission is NodesPermission => PermissionGuards.includes(permission, 'read_nodes'); + static isReplicate = (permission: Permission): permission is ReplicatePermission => + PermissionGuards.includes( + permission, + 'create_replicate', + 'read_replicate', + 'update_replicate', + 'delete_replicate' + ); static isRoles = (permission: Permission): permission is RolesPermission => PermissionGuards.includes( permission, @@ -143,6 +153,11 @@ export class Map { nodes: permission, action, })); + } else if (PermissionGuards.isReplicate(permission)) { + return Array.from(permission.actions).map((action) => ({ + replicate: permission, + action, + })); } else if (PermissionGuards.isRoles(permission)) { return Array.from(permission.actions).map((action) => ({ roles: permission, action })); } else if (PermissionGuards.isTenants(permission)) { @@ -218,6 +233,7 @@ class PermissionsMapping { data: {}, groups: {}, nodes: {}, + replicate: {}, roles: {}, tenants: {}, users: {}, @@ -242,6 +258,7 @@ class PermissionsMapping { dataPermissions: Object.values(this.mappings.data), groupsPermissions: Object.values(this.mappings.groups), nodesPermissions: Object.values(this.mappings.nodes), + replicatePermissions: Object.values(this.mappings.replicate), rolesPermissions: Object.values(this.mappings.roles), tenantsPermissions: Object.values(this.mappings.tenants), usersPermissions: Object.values(this.mappings.users), @@ -325,6 +342,18 @@ class PermissionsMapping { } }; + private replicate = (permission: WeaviatePermission) => { + if (permission.replicate !== undefined) { + const { collection, shard } = permission.replicate; + if (collection === undefined) throw new Error('Replicate permission missing collection'); + if (shard === undefined) throw new Error('Replicate permission missing shard'); + const key = `${collection}#${shard}`; + if (this.mappings.replicate[key] === undefined) + this.mappings.replicate[key] = { collection, shard, actions: [] }; + this.mappings.replicate[key].actions.push(permission.action as ReplicateAction); + } + }; + private roles = (permission: WeaviatePermission) => { if (permission.roles !== undefined) { const key = permission.roles.role; @@ -362,6 +391,7 @@ class PermissionsMapping { this.data(permission); this.groups(permission); this.nodes(permission); + this.replicate(permission); this.roles(permission); this.tenants(permission); this.users(permission); @@ -376,6 +406,7 @@ type PermissionMappings = { data: Record; groups: Record; nodes: Record; + replicate: Record; roles: Record; tenants: Record; users: Record; From 19fb2371a2ed4ce8a96e3dc4704c418e19ee9db7 Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 13:32:41 +0100 Subject: [PATCH 2/7] Differentiate between RQ-bits in 1.32 and 1.33 --- src/collections/config/integration.test.ts | 23 +++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/collections/config/integration.test.ts b/src/collections/config/integration.test.ts index 119d1594..79bf1e55 100644 --- a/src/collections/config/integration.test.ts +++ b/src/collections/config/integration.test.ts @@ -880,7 +880,28 @@ describe('Testing of the collection.config namespace', () => { }); requireAtLeast(1, 32, 0).it( - 'should be able to create a collection with RQ quantizer bits option', + 'should be able to create a collection with RQ quantizer bits=8 option', + async () => { + const collectionName = 'TestCollectionRQQuantizerBits'; + const collection = await client.collections.create({ + name: collectionName, + vectorizers: weaviate.configure.vectors.selfProvided({ + quantizer: weaviate.configure.vectorIndex.quantizer.rq({ bits: 8, rescoreLimit: 10 }), + }), + }); + await collection.config.get().then((config) => { + console.log(JSON.stringify(config, null, 2)); + const indexConfig = config.vectorizers.default.indexConfig as VectorIndexConfigHNSW; + expect(indexConfig.quantizer).toBeDefined(); + expect(indexConfig.quantizer?.type).toEqual('rq'); + expect((indexConfig.quantizer as RQConfig).bits).toEqual(8); + expect((indexConfig.quantizer as RQConfig).rescoreLimit).toEqual(10); + }); + } + ); + + requireAtLeast(1, 33, 0).it( + 'should be able to create a collection with RQ quantizer bits=1 option', async () => { const collectionName = 'TestCollectionRQQuantizerBits'; const collection = await client.collections.create({ From f437d321f312bfa594783eba363224aacde8b878 Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 13:33:23 +0100 Subject: [PATCH 3/7] Update CI images --- .github/workflows/main.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 11c9ec5d..3979846e 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -10,10 +10,10 @@ env: WEAVIATE_127: 1.27.27 WEAVIATE_128: 1.28.16 WEAVIATE_129: 1.29.9 - WEAVIATE_130: 1.30.12 - WEAVIATE_131: 1.31.5 - WEAVIATE_132: 1.32.5 - WEAVIATE_133: 1.33.0-rc.1 + WEAVIATE_130: 1.30.17 + WEAVIATE_131: 1.31.16 + WEAVIATE_132: 1.32.10 + WEAVIATE_133: 1.33.0 concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} From 27aeca9ca3e8b4ed70c1c1468779ef1971d39661 Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 14:00:41 +0100 Subject: [PATCH 4/7] Allow runtime generation with images and cohere module --- src/collections/serialize/index.ts | 69 +++++++---- src/proto/v1/generative.ts | 187 ++++++++++++++++++++++++++++ src/proto/v1/health_weaviate.ts | 192 +++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+), 23 deletions(-) create mode 100644 src/proto/v1/health_weaviate.ts diff --git a/src/collections/serialize/index.ts b/src/collections/serialize/index.ts index 815c8b50..aa63bed9 100644 --- a/src/collections/serialize/index.ts +++ b/src/collections/serialize/index.ts @@ -815,40 +815,51 @@ export class Serialize { return vec !== undefined && !Array.isArray(vec) && Object.values(vec).some(ArrayInputGuards.is2DArray); }; + private static withImages = async >( + config: T, + imgs?: (string | Buffer)[], + imgProps?: string[] + ): Promise => { + if (imgs == undefined && imgProps == undefined) { + return config; + } + return { + ...config, + images: TextArray.fromPartial({ + values: imgs ? await Promise.all(imgs.map(toBase64FromMedia)) : undefined, + }), + imageProperties: TextArray.fromPartial({ values: imgProps }), + }; + }; private static generativeQuery = async ( generative: GenerativeConfigRuntime, opts?: { metadata?: boolean; images?: (string | Buffer)[]; imageProperties?: string[] } ): Promise => { - const withImages = async >( - config: T, - imgs?: (string | Buffer)[], - imgProps?: string[] - ): Promise => { - if (imgs == undefined && imgProps == undefined) { - return config; - } - return { - ...config, - images: TextArray.fromPartial({ - values: imgs ? await Promise.all(imgs.map(toBase64FromMedia)) : undefined, - }), - imageProperties: TextArray.fromPartial({ values: imgProps }), - }; - }; - const provider = GenerativeProvider.fromPartial({ returnMetadata: opts?.metadata }); switch (generative.name) { case 'generative-anthropic': - provider.anthropic = await withImages(generative.config || {}, opts?.images, opts?.imageProperties); + provider.anthropic = await Serialize.withImages( + generative.config || {}, + opts?.images, + opts?.imageProperties + ); break; case 'generative-anyscale': provider.anyscale = generative.config || {}; break; case 'generative-aws': - provider.aws = await withImages(generative.config || {}, opts?.images, opts?.imageProperties); + provider.aws = await Serialize.withImages( + generative.config || {}, + opts?.images, + opts?.imageProperties + ); break; case 'generative-cohere': - provider.cohere = generative.config || {}; + provider.cohere = await Serialize.withImages( + generative.config || {}, + opts?.images, + opts?.imageProperties + ); break; case 'generative-databricks': provider.databricks = generative.config || {}; @@ -860,7 +871,11 @@ export class Serialize { provider.friendliai = generative.config || {}; break; case 'generative-google': - provider.google = await withImages(generative.config || {}, opts?.images, opts?.imageProperties); + provider.google = await Serialize.withImages( + generative.config || {}, + opts?.images, + opts?.imageProperties + ); break; case 'generative-mistral': provider.mistral = generative.config || {}; @@ -869,10 +884,18 @@ export class Serialize { provider.nvidia = generative.config || {}; break; case 'generative-ollama': - provider.ollama = await withImages(generative.config || {}, opts?.images, opts?.imageProperties); + provider.ollama = await Serialize.withImages( + generative.config || {}, + opts?.images, + opts?.imageProperties + ); break; case 'generative-openai': - provider.openai = await withImages(generative.config || {}, opts?.images, opts?.imageProperties); + provider.openai = await Serialize.withImages( + generative.config || {}, + opts?.images, + opts?.imageProperties + ); break; } return provider; diff --git a/src/proto/v1/generative.ts b/src/proto/v1/generative.ts index 7cf1e35c..14c499f8 100644 --- a/src/proto/v1/generative.ts +++ b/src/proto/v1/generative.ts @@ -84,6 +84,7 @@ export interface GenerativeAWS { targetVariant?: string | undefined; images?: TextArray | undefined; imageProperties?: TextArray | undefined; + maxTokens?: number | undefined; } export interface GenerativeCohere { @@ -96,6 +97,8 @@ export interface GenerativeCohere { presencePenalty?: number | undefined; stopSequences?: TextArray | undefined; temperature?: number | undefined; + images?: TextArray | undefined; + imageProperties?: TextArray | undefined; } export interface GenerativeDummy { @@ -133,6 +136,104 @@ export interface GenerativeOpenAI { isAzure?: boolean | undefined; images?: TextArray | undefined; imageProperties?: TextArray | undefined; + reasoningEffort?: GenerativeOpenAI_ReasoningEffort | undefined; + verbosity?: GenerativeOpenAI_Verbosity | undefined; +} + +export enum GenerativeOpenAI_ReasoningEffort { + REASONING_EFFORT_UNSPECIFIED = 0, + REASONING_EFFORT_MINIMAL = 1, + REASONING_EFFORT_LOW = 2, + REASONING_EFFORT_MEDIUM = 3, + REASONING_EFFORT_HIGH = 4, + UNRECOGNIZED = -1, +} + +export function generativeOpenAI_ReasoningEffortFromJSON(object: any): GenerativeOpenAI_ReasoningEffort { + switch (object) { + case 0: + case "REASONING_EFFORT_UNSPECIFIED": + return GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_UNSPECIFIED; + case 1: + case "REASONING_EFFORT_MINIMAL": + return GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_MINIMAL; + case 2: + case "REASONING_EFFORT_LOW": + return GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_LOW; + case 3: + case "REASONING_EFFORT_MEDIUM": + return GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_MEDIUM; + case 4: + case "REASONING_EFFORT_HIGH": + return GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_HIGH; + case -1: + case "UNRECOGNIZED": + default: + return GenerativeOpenAI_ReasoningEffort.UNRECOGNIZED; + } +} + +export function generativeOpenAI_ReasoningEffortToJSON(object: GenerativeOpenAI_ReasoningEffort): string { + switch (object) { + case GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_UNSPECIFIED: + return "REASONING_EFFORT_UNSPECIFIED"; + case GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_MINIMAL: + return "REASONING_EFFORT_MINIMAL"; + case GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_LOW: + return "REASONING_EFFORT_LOW"; + case GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_MEDIUM: + return "REASONING_EFFORT_MEDIUM"; + case GenerativeOpenAI_ReasoningEffort.REASONING_EFFORT_HIGH: + return "REASONING_EFFORT_HIGH"; + case GenerativeOpenAI_ReasoningEffort.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } +} + +export enum GenerativeOpenAI_Verbosity { + VERBOSITY_UNSPECIFIED = 0, + VERBOSITY_LOW = 1, + VERBOSITY_MEDIUM = 2, + VERBOSITY_HIGH = 3, + UNRECOGNIZED = -1, +} + +export function generativeOpenAI_VerbosityFromJSON(object: any): GenerativeOpenAI_Verbosity { + switch (object) { + case 0: + case "VERBOSITY_UNSPECIFIED": + return GenerativeOpenAI_Verbosity.VERBOSITY_UNSPECIFIED; + case 1: + case "VERBOSITY_LOW": + return GenerativeOpenAI_Verbosity.VERBOSITY_LOW; + case 2: + case "VERBOSITY_MEDIUM": + return GenerativeOpenAI_Verbosity.VERBOSITY_MEDIUM; + case 3: + case "VERBOSITY_HIGH": + return GenerativeOpenAI_Verbosity.VERBOSITY_HIGH; + case -1: + case "UNRECOGNIZED": + default: + return GenerativeOpenAI_Verbosity.UNRECOGNIZED; + } +} + +export function generativeOpenAI_VerbosityToJSON(object: GenerativeOpenAI_Verbosity): string { + switch (object) { + case GenerativeOpenAI_Verbosity.VERBOSITY_UNSPECIFIED: + return "VERBOSITY_UNSPECIFIED"; + case GenerativeOpenAI_Verbosity.VERBOSITY_LOW: + return "VERBOSITY_LOW"; + case GenerativeOpenAI_Verbosity.VERBOSITY_MEDIUM: + return "VERBOSITY_MEDIUM"; + case GenerativeOpenAI_Verbosity.VERBOSITY_HIGH: + return "VERBOSITY_HIGH"; + case GenerativeOpenAI_Verbosity.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } } export interface GenerativeGoogle { @@ -1270,6 +1371,7 @@ function createBaseGenerativeAWS(): GenerativeAWS { targetVariant: undefined, images: undefined, imageProperties: undefined, + maxTokens: undefined, }; } @@ -1302,6 +1404,9 @@ export const GenerativeAWS = { if (message.imageProperties !== undefined) { TextArray.encode(message.imageProperties, writer.uint32(122).fork()).ldelim(); } + if (message.maxTokens !== undefined) { + writer.uint32(128).int64(message.maxTokens); + } return writer; }, @@ -1375,6 +1480,13 @@ export const GenerativeAWS = { message.imageProperties = TextArray.decode(reader, reader.uint32()); continue; + case 16: + if (tag !== 128) { + break; + } + + message.maxTokens = longToNumber(reader.int64() as Long); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -1395,6 +1507,7 @@ export const GenerativeAWS = { targetVariant: isSet(object.targetVariant) ? globalThis.String(object.targetVariant) : undefined, images: isSet(object.images) ? TextArray.fromJSON(object.images) : undefined, imageProperties: isSet(object.imageProperties) ? TextArray.fromJSON(object.imageProperties) : undefined, + maxTokens: isSet(object.maxTokens) ? globalThis.Number(object.maxTokens) : undefined, }; }, @@ -1427,6 +1540,9 @@ export const GenerativeAWS = { if (message.imageProperties !== undefined) { obj.imageProperties = TextArray.toJSON(message.imageProperties); } + if (message.maxTokens !== undefined) { + obj.maxTokens = Math.round(message.maxTokens); + } return obj; }, @@ -1448,6 +1564,7 @@ export const GenerativeAWS = { message.imageProperties = (object.imageProperties !== undefined && object.imageProperties !== null) ? TextArray.fromPartial(object.imageProperties) : undefined; + message.maxTokens = object.maxTokens ?? undefined; return message; }, }; @@ -1463,6 +1580,8 @@ function createBaseGenerativeCohere(): GenerativeCohere { presencePenalty: undefined, stopSequences: undefined, temperature: undefined, + images: undefined, + imageProperties: undefined, }; } @@ -1495,6 +1614,12 @@ export const GenerativeCohere = { if (message.temperature !== undefined) { writer.uint32(73).double(message.temperature); } + if (message.images !== undefined) { + TextArray.encode(message.images, writer.uint32(82).fork()).ldelim(); + } + if (message.imageProperties !== undefined) { + TextArray.encode(message.imageProperties, writer.uint32(90).fork()).ldelim(); + } return writer; }, @@ -1568,6 +1693,20 @@ export const GenerativeCohere = { message.temperature = reader.double(); continue; + case 10: + if (tag !== 82) { + break; + } + + message.images = TextArray.decode(reader, reader.uint32()); + continue; + case 11: + if (tag !== 90) { + break; + } + + message.imageProperties = TextArray.decode(reader, reader.uint32()); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -1588,6 +1727,8 @@ export const GenerativeCohere = { presencePenalty: isSet(object.presencePenalty) ? globalThis.Number(object.presencePenalty) : undefined, stopSequences: isSet(object.stopSequences) ? TextArray.fromJSON(object.stopSequences) : undefined, temperature: isSet(object.temperature) ? globalThis.Number(object.temperature) : undefined, + images: isSet(object.images) ? TextArray.fromJSON(object.images) : undefined, + imageProperties: isSet(object.imageProperties) ? TextArray.fromJSON(object.imageProperties) : undefined, }; }, @@ -1620,6 +1761,12 @@ export const GenerativeCohere = { if (message.temperature !== undefined) { obj.temperature = message.temperature; } + if (message.images !== undefined) { + obj.images = TextArray.toJSON(message.images); + } + if (message.imageProperties !== undefined) { + obj.imageProperties = TextArray.toJSON(message.imageProperties); + } return obj; }, @@ -1639,6 +1786,12 @@ export const GenerativeCohere = { ? TextArray.fromPartial(object.stopSequences) : undefined; message.temperature = object.temperature ?? undefined; + message.images = (object.images !== undefined && object.images !== null) + ? TextArray.fromPartial(object.images) + : undefined; + message.imageProperties = (object.imageProperties !== undefined && object.imageProperties !== null) + ? TextArray.fromPartial(object.imageProperties) + : undefined; return message; }, }; @@ -1951,6 +2104,8 @@ function createBaseGenerativeOpenAI(): GenerativeOpenAI { isAzure: undefined, images: undefined, imageProperties: undefined, + reasoningEffort: undefined, + verbosity: undefined, }; } @@ -2001,6 +2156,12 @@ export const GenerativeOpenAI = { if (message.imageProperties !== undefined) { TextArray.encode(message.imageProperties, writer.uint32(122).fork()).ldelim(); } + if (message.reasoningEffort !== undefined) { + writer.uint32(128).int32(message.reasoningEffort); + } + if (message.verbosity !== undefined) { + writer.uint32(136).int32(message.verbosity); + } return writer; }, @@ -2116,6 +2277,20 @@ export const GenerativeOpenAI = { message.imageProperties = TextArray.decode(reader, reader.uint32()); continue; + case 16: + if (tag !== 128) { + break; + } + + message.reasoningEffort = reader.int32() as any; + continue; + case 17: + if (tag !== 136) { + break; + } + + message.verbosity = reader.int32() as any; + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -2142,6 +2317,10 @@ export const GenerativeOpenAI = { isAzure: isSet(object.isAzure) ? globalThis.Boolean(object.isAzure) : undefined, images: isSet(object.images) ? TextArray.fromJSON(object.images) : undefined, imageProperties: isSet(object.imageProperties) ? TextArray.fromJSON(object.imageProperties) : undefined, + reasoningEffort: isSet(object.reasoningEffort) + ? generativeOpenAI_ReasoningEffortFromJSON(object.reasoningEffort) + : undefined, + verbosity: isSet(object.verbosity) ? generativeOpenAI_VerbosityFromJSON(object.verbosity) : undefined, }; }, @@ -2192,6 +2371,12 @@ export const GenerativeOpenAI = { if (message.imageProperties !== undefined) { obj.imageProperties = TextArray.toJSON(message.imageProperties); } + if (message.reasoningEffort !== undefined) { + obj.reasoningEffort = generativeOpenAI_ReasoningEffortToJSON(message.reasoningEffort); + } + if (message.verbosity !== undefined) { + obj.verbosity = generativeOpenAI_VerbosityToJSON(message.verbosity); + } return obj; }, @@ -2219,6 +2404,8 @@ export const GenerativeOpenAI = { message.imageProperties = (object.imageProperties !== undefined && object.imageProperties !== null) ? TextArray.fromPartial(object.imageProperties) : undefined; + message.reasoningEffort = object.reasoningEffort ?? undefined; + message.verbosity = object.verbosity ?? undefined; return message; }, }; diff --git a/src/proto/v1/health_weaviate.ts b/src/proto/v1/health_weaviate.ts new file mode 100644 index 00000000..ae92e40a --- /dev/null +++ b/src/proto/v1/health_weaviate.ts @@ -0,0 +1,192 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v1.176.0 +// protoc v3.19.1 +// source: v1/health_weaviate.proto + +/* eslint-disable */ +import _m0 from "protobufjs/minimal.js"; + +export const protobufPackage = "weaviate.v1"; + +export interface WeaviateHealthCheckRequest { + service: string; +} + +/** + * keep compatibility with google health check + * protolint:disable ENUM_FIELD_NAMES_PREFIX + * protolint:disable ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH + */ +export interface WeaviateHealthCheckResponse { + status: WeaviateHealthCheckResponse_ServingStatus; +} + +export enum WeaviateHealthCheckResponse_ServingStatus { + UNKNOWN = 0, + SERVING = 1, + NOT_SERVING = 2, + UNRECOGNIZED = -1, +} + +export function weaviateHealthCheckResponse_ServingStatusFromJSON( + object: any, +): WeaviateHealthCheckResponse_ServingStatus { + switch (object) { + case 0: + case "UNKNOWN": + return WeaviateHealthCheckResponse_ServingStatus.UNKNOWN; + case 1: + case "SERVING": + return WeaviateHealthCheckResponse_ServingStatus.SERVING; + case 2: + case "NOT_SERVING": + return WeaviateHealthCheckResponse_ServingStatus.NOT_SERVING; + case -1: + case "UNRECOGNIZED": + default: + return WeaviateHealthCheckResponse_ServingStatus.UNRECOGNIZED; + } +} + +export function weaviateHealthCheckResponse_ServingStatusToJSON( + object: WeaviateHealthCheckResponse_ServingStatus, +): string { + switch (object) { + case WeaviateHealthCheckResponse_ServingStatus.UNKNOWN: + return "UNKNOWN"; + case WeaviateHealthCheckResponse_ServingStatus.SERVING: + return "SERVING"; + case WeaviateHealthCheckResponse_ServingStatus.NOT_SERVING: + return "NOT_SERVING"; + case WeaviateHealthCheckResponse_ServingStatus.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } +} + +function createBaseWeaviateHealthCheckRequest(): WeaviateHealthCheckRequest { + return { service: "" }; +} + +export const WeaviateHealthCheckRequest = { + encode(message: WeaviateHealthCheckRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.service !== "") { + writer.uint32(10).string(message.service); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): WeaviateHealthCheckRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseWeaviateHealthCheckRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.service = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): WeaviateHealthCheckRequest { + return { service: isSet(object.service) ? globalThis.String(object.service) : "" }; + }, + + toJSON(message: WeaviateHealthCheckRequest): unknown { + const obj: any = {}; + if (message.service !== "") { + obj.service = message.service; + } + return obj; + }, + + create(base?: DeepPartial): WeaviateHealthCheckRequest { + return WeaviateHealthCheckRequest.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): WeaviateHealthCheckRequest { + const message = createBaseWeaviateHealthCheckRequest(); + message.service = object.service ?? ""; + return message; + }, +}; + +function createBaseWeaviateHealthCheckResponse(): WeaviateHealthCheckResponse { + return { status: 0 }; +} + +export const WeaviateHealthCheckResponse = { + encode(message: WeaviateHealthCheckResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.status !== 0) { + writer.uint32(8).int32(message.status); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): WeaviateHealthCheckResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseWeaviateHealthCheckResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 8) { + break; + } + + message.status = reader.int32() as any; + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): WeaviateHealthCheckResponse { + return { status: isSet(object.status) ? weaviateHealthCheckResponse_ServingStatusFromJSON(object.status) : 0 }; + }, + + toJSON(message: WeaviateHealthCheckResponse): unknown { + const obj: any = {}; + if (message.status !== 0) { + obj.status = weaviateHealthCheckResponse_ServingStatusToJSON(message.status); + } + return obj; + }, + + create(base?: DeepPartial): WeaviateHealthCheckResponse { + return WeaviateHealthCheckResponse.fromPartial(base ?? {}); + }, + fromPartial(object: DeepPartial): WeaviateHealthCheckResponse { + const message = createBaseWeaviateHealthCheckResponse(); + message.status = object.status ?? 0; + return message; + }, +}; + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; + +export type DeepPartial = T extends Builtin ? T + : T extends globalThis.Array ? globalThis.Array> + : T extends ReadonlyArray ? ReadonlyArray> + : T extends {} ? { [K in keyof T]?: DeepPartial } + : Partial; + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} From e387fedc6c89ce295920e26b77c1738aefd7f903 Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 14:36:03 +0100 Subject: [PATCH 5/7] Fix names in tests --- src/collections/config/integration.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/collections/config/integration.test.ts b/src/collections/config/integration.test.ts index 79bf1e55..5836fd1c 100644 --- a/src/collections/config/integration.test.ts +++ b/src/collections/config/integration.test.ts @@ -882,7 +882,7 @@ describe('Testing of the collection.config namespace', () => { requireAtLeast(1, 32, 0).it( 'should be able to create a collection with RQ quantizer bits=8 option', async () => { - const collectionName = 'TestCollectionRQQuantizerBits'; + const collectionName = 'TestCollectionRQQuantizer8Bits'; const collection = await client.collections.create({ name: collectionName, vectorizers: weaviate.configure.vectors.selfProvided({ @@ -903,7 +903,7 @@ describe('Testing of the collection.config namespace', () => { requireAtLeast(1, 33, 0).it( 'should be able to create a collection with RQ quantizer bits=1 option', async () => { - const collectionName = 'TestCollectionRQQuantizerBits'; + const collectionName = 'TestCollectionRQQuantizer1Bits'; const collection = await client.collections.create({ name: collectionName, vectorizers: weaviate.configure.vectors.selfProvided({ From 0d151f32a20adaab77e6d2ab2e1d4f871955afcb Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 14:37:32 +0100 Subject: [PATCH 6/7] Skip failing test due to server regression --- src/collections/backup/integration.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/collections/backup/integration.test.ts b/src/collections/backup/integration.test.ts index cfccb2cf..a50eb5b0 100644 --- a/src/collections/backup/integration.test.ts +++ b/src/collections/backup/integration.test.ts @@ -118,7 +118,7 @@ describe('Integration testing of backups', () => { .then(testCollectionWaitForCompletion) .then(testCollectionNoWaitForCompletion)); - requireAtLeast(1, 32, 3).describe('overwrite alias', () => { + requireAtLeast(1, 32, 0).describe('overwrite alias', () => { test('overwriteAlias=true', async () => { const client = await clientPromise; @@ -153,7 +153,8 @@ describe('Integration testing of backups', () => { expect(alias.collection).toEqual(things.name); }); - test('overwriteAlias=false', async () => { + // Skip until server regression is fixed for overwriteAlias=false backups + test.skip('overwriteAlias=false', async () => { const client = await clientPromise; const things = await client.collections.create({ name: 'ThingsFalse' }); From 4c01469999af5387ffa6fc417ddf32ab6a91e0d8 Mon Sep 17 00:00:00 2001 From: Tommy Smith Date: Fri, 26 Sep 2025 15:37:50 +0100 Subject: [PATCH 7/7] Fix docstring for alias.update --- src/alias/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alias/index.ts b/src/alias/index.ts index 2ec31f21..e910d8cf 100644 --- a/src/alias/index.ts +++ b/src/alias/index.ts @@ -38,7 +38,7 @@ export interface Aliases { * delete the alias and create a new one. * * @param {string} args.alias Alias to update. - * @param {string} args.collection New collection the alias should point to. + * @param {string} args.newTargetCollection New collection the alias should point to. * @return {Promise} Awaitable promise. */ update: (args: UpdateAliasArgs) => Promise;