From 339d156dba6744fb19355cf6d63c1342c51e9001 Mon Sep 17 00:00:00 2001 From: Osama Ansar Date: Mon, 14 Sep 2026 12:28:41 +0500 Subject: [PATCH 1/2] fix(data): guard deleteMany uuid stringify, guard journey afterAll A BatchDeleteObject's uuid can come back empty from the server; stringify() then throws an opaque TypeError instead of a usable error. Only stringify when the bytes are a well-formed 16-byte uuid, otherwise report id as undefined. DeleteManyObject.id widens to optional to match. Also guard journey.test.ts's afterAll so a beforeAll failure doesn't mask itself behind a second, unrelated TypeError from an undefined client. Both were flagged in #470 as confirmed, independent bugs found while investigating the tests-without-auth flake. --- src/collections/deserialize/index.ts | 5 +++- src/collections/deserialize/unit.test.ts | 30 ++++++++++++++++++++++++ src/collections/types/data.ts | 3 ++- test/collections/journey.test.ts | 2 +- 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/collections/deserialize/unit.test.ts diff --git a/src/collections/deserialize/index.ts b/src/collections/deserialize/index.ts index 5ad7489e..97723179 100644 --- a/src/collections/deserialize/index.ts +++ b/src/collections/deserialize/index.ts @@ -533,7 +533,10 @@ export class Deserialize { objects: verbose ? reply.objects.map((obj) => { return { - id: stringify(obj.uuid), + // stringify() throws on anything but a 16-byte uuid; the server + // can omit the uuid on a BatchDeleteObject, so guard it here + // instead of letting an opaque TypeError escape. + id: obj.uuid.length === 16 ? stringify(obj.uuid) : undefined, successful: obj.successful, error: obj.error, }; diff --git a/src/collections/deserialize/unit.test.ts b/src/collections/deserialize/unit.test.ts new file mode 100644 index 00000000..19581ff8 --- /dev/null +++ b/src/collections/deserialize/unit.test.ts @@ -0,0 +1,30 @@ +import { v4 } from 'uuid'; +import { describe, expect, it } from 'vitest'; +import { BatchDeleteReply } from '../../proto/v1/batch_delete.js'; +import { Deserialize } from './index.js'; + +describe('Unit testing of Deserialize.deleteMany', () => { + const baseReply = (uuid: Uint8Array): BatchDeleteReply => ({ + took: 0, + failed: 0, + matches: 1, + successful: 1, + objects: [{ uuid, successful: true, error: '' }], + }); + + it('should stringify a well-formed 16-byte uuid', () => { + const id = v4(); + const uuid = Uint8Array.from(Buffer.from(id.replace(/-/g, ''), 'hex')); + + const result = Deserialize.deleteMany(baseReply(uuid), true); + + expect(result.objects![0].id).toBe(id); + }); + + it('should return an undefined id instead of throwing when the server omits the uuid', () => { + const result = Deserialize.deleteMany(baseReply(new Uint8Array(0)), true); + + expect(result.objects![0].id).toBeUndefined(); + expect(result.objects![0].successful).toBe(true); + }); +}); diff --git a/src/collections/types/data.ts b/src/collections/types/data.ts index 0a4d33be..763ab3a7 100644 --- a/src/collections/types/data.ts +++ b/src/collections/types/data.ts @@ -9,7 +9,8 @@ export type DataObject = { }; export type DeleteManyObject = { - id: string; + /** Undefined when the server returned no uuid for this object. */ + id?: string; successful: boolean; error?: string; }; diff --git a/test/collections/journey.test.ts b/test/collections/journey.test.ts index 11d01222..094bdd83 100644 --- a/test/collections/journey.test.ts +++ b/test/collections/journey.test.ts @@ -13,7 +13,7 @@ describe('Journey testing of the client using a WCD cluster', () => { dateOfBirth: Date; }; - afterAll(() => client.collections.delete(collectionName)); + afterAll(() => client?.collections.delete(collectionName)); beforeAll(async () => { client = await weaviate.connectToWeaviateCloud( From 5bea9d420e0a04c4da8f8c90f05d2b99433c7a87 Mon Sep 17 00:00:00 2001 From: Osama Ansar Date: Tue, 15 Sep 2026 13:36:02 +0500 Subject: [PATCH 2/2] feat(generative): add configure.generative.meta() module config builder Weaviate v1.39.3 adds a generative-meta module (baseURL, model, temperature, topP, maxTokens, frequencyPenalty, presencePenalty, reasoningEffort). Wires it through the same builder pattern as the other generative-* modules: config/types, configure/types, the builder function, and unit tests. --- src/collections/config/types/generative.ts | 15 ++++++++ src/collections/configure/generative.ts | 18 ++++++++++ src/collections/configure/types/generative.ts | 6 ++++ src/collections/configure/unit.test.ts | 35 +++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/src/collections/config/types/generative.ts b/src/collections/config/types/generative.ts index 3b3b7363..d05fd355 100644 --- a/src/collections/config/types/generative.ts +++ b/src/collections/config/types/generative.ts @@ -115,6 +115,17 @@ export type GenerativeContextualAIConfig = { avoidCommentary?: boolean; }; +export type GenerativeMetaConfig = { + baseURL?: string; + model?: string; + temperature?: number; + topP?: number; + maxTokens?: number; + frequencyPenalty?: number; + presencePenalty?: number; + reasoningEffort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'; +}; + export type GenerativeConfig = | GenerativeAnthropicConfig | GenerativeAnyscaleConfig @@ -125,6 +136,7 @@ export type GenerativeConfig = | GenerativeDatabricksConfig | GenerativeGoogleConfig | GenerativeFriendliAIConfig + | GenerativeMetaConfig | GenerativeMistralConfig | GenerativeOllamaConfig | GenerativeOpenAIConfig @@ -151,6 +163,8 @@ export type GenerativeConfigType = G extends 'generative-anthropic' ? GenerativeGoogleConfig : G extends 'generative-friendliai' ? GenerativeFriendliAIConfig + : G extends 'generative-meta' + ? GenerativeMetaConfig : G extends 'generative-mistral' ? GenerativeMistralConfig : G extends 'generative-ollama' @@ -178,6 +192,7 @@ export type GenerativeSearch = | 'generative-databricks' | 'generative-google' | 'generative-friendliai' + | 'generative-meta' | 'generative-mistral' | 'generative-ollama' | 'generative-openai' diff --git a/src/collections/configure/generative.ts b/src/collections/configure/generative.ts index f00ca85c..246bfbdd 100644 --- a/src/collections/configure/generative.ts +++ b/src/collections/configure/generative.ts @@ -8,6 +8,7 @@ import { GenerativeDatabricksConfig, GenerativeFriendliAIConfig, GenerativeGoogleConfig, + GenerativeMetaConfig, GenerativeMistralConfig, GenerativeNvidiaConfig, GenerativeOllamaConfig, @@ -25,6 +26,7 @@ import { GenerativeContextualAIConfigCreate, GenerativeDatabricksConfigCreate, GenerativeFriendliAIConfigCreate, + GenerativeMetaConfigCreate, GenerativeMistralConfigCreate, GenerativeNvidiaConfigCreate, GenerativeOllamaConfigCreate, @@ -184,6 +186,22 @@ export default { config, }; }, + /** + * Create a `ModuleConfig<'generative-meta', GenerativeMetaConfig | undefined>` object for use when performing AI generation using the `generative-meta` module. + * + * See the [documentation](https://weaviate.io/developers/weaviate/model-providers/meta/generative) for detailed usage. + * + * @param {GenerativeMetaConfigCreate} [config] The configuration for the `generative-meta` module. + * @returns {ModuleConfig<'generative-meta', GenerativeMetaConfig | undefined>} The configuration object. + */ + meta( + config?: GenerativeMetaConfigCreate + ): ModuleConfig<'generative-meta', GenerativeMetaConfig | undefined> { + return { + name: 'generative-meta', + config, + }; + }, /** * Create a `ModuleConfig<'generative-mistral', GenerativeMistralConfig | undefined>` object for use when performing AI generation using the `generative-mistral` module. * diff --git a/src/collections/configure/types/generative.ts b/src/collections/configure/types/generative.ts index b46a0de3..2d4e48f6 100644 --- a/src/collections/configure/types/generative.ts +++ b/src/collections/configure/types/generative.ts @@ -4,6 +4,7 @@ import { GenerativeAnyscaleConfig, GenerativeDatabricksConfig, GenerativeFriendliAIConfig, + GenerativeMetaConfig, GenerativeMistralConfig, GenerativeNvidiaConfig, GenerativeOllamaConfig, @@ -44,6 +45,8 @@ export type GenerativeDatabricksConfigCreate = GenerativeDatabricksConfig; export type GenerativeFriendliAIConfigCreate = GenerativeFriendliAIConfig; +export type GenerativeMetaConfigCreate = GenerativeMetaConfig; + export type GenerativeMistralConfigCreate = GenerativeMistralConfig; export type GenerativeNvidiaConfigCreate = GenerativeNvidiaConfig; @@ -76,6 +79,7 @@ export type GenerativeConfigCreate = | GenerativeContextualAIConfigCreate | GenerativeDatabricksConfigCreate | GenerativeFriendliAIConfigCreate + | GenerativeMetaConfigCreate | GenerativeMistralConfigCreate | GenerativeNvidiaConfigCreate | GenerativeOllamaConfigCreate @@ -99,6 +103,8 @@ export type GenerativeConfigCreateType = G extends 'generative-anthropic' ? GenerativeDatabricksConfigCreate : G extends 'generative-friendliai' ? GenerativeFriendliAIConfigCreate + : G extends 'generative-meta' + ? GenerativeMetaConfigCreate : G extends 'generative-mistral' ? GenerativeMistralConfigCreate : G extends 'generative-nvidia' diff --git a/src/collections/configure/unit.test.ts b/src/collections/configure/unit.test.ts index 43e3c849..976ffb2b 100644 --- a/src/collections/configure/unit.test.ts +++ b/src/collections/configure/unit.test.ts @@ -10,6 +10,7 @@ import { GenerativeDatabricksConfig, GenerativeFriendliAIConfig, GenerativeGoogleConfig, + GenerativeMetaConfig, GenerativeMistralConfig, GenerativeOllamaConfig, GenerativeOpenAIConfig, @@ -2074,6 +2075,40 @@ describe('Unit testing of the generative factory class', () => { }); }); + it('should create the correct GenerativeMetaConfig type with required & default values', () => { + const config = configure.generative.meta(); + expect(config).toEqual>({ + name: 'generative-meta', + config: undefined, + }); + }); + + it('should create the correct GenerativeMetaConfig type with all values', () => { + const config = configure.generative.meta({ + baseURL: 'base-url', + model: 'muse-spark-1.2', + temperature: 0.5, + topP: 0.9, + maxTokens: 100, + frequencyPenalty: 0.1, + presencePenalty: 0.2, + reasoningEffort: 'medium', + }); + expect(config).toEqual>({ + name: 'generative-meta', + config: { + baseURL: 'base-url', + model: 'muse-spark-1.2', + temperature: 0.5, + topP: 0.9, + maxTokens: 100, + frequencyPenalty: 0.1, + presencePenalty: 0.2, + reasoningEffort: 'medium', + }, + }); + }); + it('should create the correct GenerativeMistralConfig type with required & default values', () => { const config = configure.generative.mistral(); expect(config).toEqual>({