Skip to content

Commit 8d9ec99

Browse files
fix: migrate Weaviate to weaviate-client v3 for agentKnowledgeVSEmbeddings compatibility (#5991) (#5993)
* fix: migrate Weaviate to weaviate-client v3 for @langchain/weaviate 1.0.1 compatibility (#5991) Root cause: Weaviate.ts used weaviate-ts-client v2 which creates a client without a collections property. @langchain/weaviate 1.0.1 expects weaviate-client v3 and calls this.client.collections.get(), causing TypeError: Cannot read properties of undefined (reading 'get'). * fix: address review feedback — deduplicate parseHostPort, fix IPv6 and HTTPS port - Remove duplicate parseHostPort from Weaviate.ts, import from weaviateClientUtils - Rewrite parseHostPort to handle bracketed IPv6 (e.g. [::1]:8080) correctly - Return port as optional (undefined when not specified) instead of hardcoded 8080 - Use nullish coalescing (??) for default port so HTTPS correctly defaults to 443 - Update tests to match new return type and add IPv6 coverage * fix weaviate connection --------- Co-authored-by: Henry <hzj94@hotmail.com>
1 parent d9b683d commit 8d9ec99

4 files changed

Lines changed: 207 additions & 114 deletions

File tree

packages/components/nodes/vectorstores/Weaviate/Weaviate.ts

Lines changed: 158 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { flatten } from 'lodash'
2-
import weaviate, { WeaviateClient, ApiKey } from 'weaviate-ts-client'
2+
import weaviate from 'weaviate-client'
33
import { WeaviateLibArgs, WeaviateStore } from '@langchain/weaviate'
44
import { Document } from '@langchain/core/documents'
55
import { Embeddings } from '@langchain/core/embeddings'
@@ -9,6 +9,76 @@ import { addMMRInputParams, resolveVectorStoreOrRetriever } from '../VectorStore
99
import { index } from '../../../src/indexing'
1010
import { VectorStore } from '@langchain/core/vectorstores'
1111

12+
/**
13+
* Parses a host string into host and optional port.
14+
* Handles IPv6 bracket notation (e.g. "[::1]:8080") and plain "host:port".
15+
*/
16+
export function parseHostPort(host: string): { host: string; port?: number } {
17+
const ipv6Match = host.match(/^\[([^\]]+)\](?::(\d+))?$/)
18+
if (ipv6Match) {
19+
const port = ipv6Match[2] ? parseInt(ipv6Match[2], 10) : undefined
20+
return { host: ipv6Match[1], port: isNaN(port as number) ? undefined : port }
21+
}
22+
const lastColon = host.lastIndexOf(':')
23+
if (lastColon > 0) {
24+
const maybePart = host.substring(lastColon + 1)
25+
const port = parseInt(maybePart, 10)
26+
if (!isNaN(port) && String(port) === maybePart) {
27+
return { host: host.substring(0, lastColon), port }
28+
}
29+
}
30+
return { host }
31+
}
32+
33+
async function createWeaviateClient(
34+
weaviateConnectionType: string,
35+
rawHost: string,
36+
httpSecure?: boolean,
37+
rawGrpcHost?: string,
38+
grpcSecure?: boolean,
39+
apiKey?: string
40+
): Promise<Awaited<ReturnType<typeof weaviate.connectToCustom>>> {
41+
if (weaviateConnectionType === 'cloud') {
42+
if (!apiKey) {
43+
throw new Error('API key is required for cloud connection')
44+
}
45+
return weaviate.connectToWeaviateCloud(rawHost, {
46+
authCredentials: new weaviate.ApiKey(apiKey)
47+
})
48+
}
49+
50+
const { host: extractedHttpHost, port: extractedHttpPort } = parseHostPort(rawHost)
51+
const { host: extractedGrpcHost, port: extractedGrpcPort } = parseHostPort(rawGrpcHost ?? '')
52+
53+
if (weaviateConnectionType === 'local') {
54+
const options: Parameters<typeof weaviate.connectToLocal>[0] = {
55+
host: extractedHttpHost,
56+
port: extractedHttpPort,
57+
grpcPort: extractedGrpcPort,
58+
authCredentials: apiKey ? new weaviate.ApiKey(apiKey) : undefined
59+
}
60+
return weaviate.connectToLocal(options)
61+
}
62+
63+
const httpHost = extractedHttpHost
64+
const httpPort = extractedHttpPort ?? 8080
65+
66+
const grpcHost = extractedGrpcHost
67+
const grpcPort = extractedGrpcPort ?? 50051
68+
69+
const options: Parameters<typeof weaviate.connectToCustom>[0] = {
70+
httpHost,
71+
httpPort,
72+
httpSecure,
73+
grpcHost,
74+
grpcPort,
75+
grpcSecure,
76+
authCredentials: apiKey ? new weaviate.ApiKey(apiKey) : undefined
77+
}
78+
79+
return weaviate.connectToCustom(options)
80+
}
81+
1282
class Weaviate_VectorStores implements INode {
1383
label: string
1484
name: string
@@ -26,7 +96,7 @@ class Weaviate_VectorStores implements INode {
2696
constructor() {
2797
this.label = 'Weaviate'
2898
this.name = 'weaviate'
29-
this.version = 4.0
99+
this.version = 5.0
30100
this.type = 'Weaviate'
31101
this.icon = 'weaviate.png'
32102
this.category = 'Vector Stores'
@@ -62,32 +132,71 @@ class Weaviate_VectorStores implements INode {
62132
optional: true
63133
},
64134
{
65-
label: 'Weaviate Scheme',
66-
name: 'weaviateScheme',
135+
label: 'Weaviate Connection Type',
136+
name: 'weaviateConnectionType',
67137
type: 'options',
68-
default: 'https',
69138
options: [
70139
{
71-
label: 'https',
72-
name: 'https'
140+
label: 'Cloud',
141+
name: 'cloud'
73142
},
74143
{
75-
label: 'http',
76-
name: 'http'
144+
label: 'Local',
145+
name: 'local'
146+
},
147+
{
148+
label: 'Custom',
149+
name: 'custom'
77150
}
78-
]
151+
],
152+
default: 'cloud'
79153
},
80154
{
81-
label: 'Weaviate Host',
155+
label: 'Weaviate Host/URL',
82156
name: 'weaviateHost',
83157
type: 'string',
84-
placeholder: 'localhost:8080'
158+
placeholder: 'localhost:8080',
159+
description: 'The host/URL to connect to the Weaviate server. Use REST Endpoint for cloud connection.'
160+
},
161+
{
162+
label: 'HTTP Secure',
163+
name: 'weaviateHttpSecure',
164+
type: 'boolean',
165+
default: true,
166+
additionalParams: true,
167+
optional: true,
168+
show: {
169+
weaviateConnectionType: 'custom'
170+
}
171+
},
172+
{
173+
label: 'GRPC Host/URL',
174+
name: 'weaviateGrpcHost',
175+
type: 'string',
176+
placeholder: 'localhost:50051',
177+
additionalParams: true,
178+
optional: true,
179+
show: {
180+
weaviateConnectionType: 'custom'
181+
}
182+
},
183+
{
184+
label: 'GRPC Secure',
185+
name: 'weaviateGrpcSecure',
186+
type: 'boolean',
187+
default: true,
188+
additionalParams: true,
189+
optional: true,
190+
show: {
191+
weaviateConnectionType: 'custom'
192+
}
85193
},
86194
{
87195
label: 'Weaviate Index',
88196
name: 'weaviateIndex',
89197
type: 'string',
90-
placeholder: 'Test'
198+
placeholder: 'Test',
199+
description: 'The collection name to use. Must start with capital letter.'
91200
},
92201
{
93202
label: 'Weaviate Text Key',
@@ -152,8 +261,11 @@ class Weaviate_VectorStores implements INode {
152261
//@ts-ignore
153262
vectorStoreMethods = {
154263
async upsert(nodeData: INodeData, options: ICommonObject): Promise<Partial<IndexingResult>> {
155-
const weaviateScheme = nodeData.inputs?.weaviateScheme as string
156264
const weaviateHost = nodeData.inputs?.weaviateHost as string
265+
const weaviateGrpcHost = nodeData.inputs?.weaviateGrpcHost as string
266+
const weaviateHttpSecure = nodeData.inputs?.weaviateHttpSecure as boolean
267+
const weaviateGrpcSecure = nodeData.inputs?.weaviateGrpcSecure as boolean
268+
const weaviateConnectionType = nodeData.inputs?.weaviateConnectionType as string
157269
const weaviateIndex = nodeData.inputs?.weaviateIndex as string
158270
const weaviateTextKey = nodeData.inputs?.weaviateTextKey as string
159271
const weaviateMetadataKeys = nodeData.inputs?.weaviateMetadataKeys as string
@@ -164,14 +276,14 @@ class Weaviate_VectorStores implements INode {
164276
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
165277
const weaviateApiKey = getCredentialParam('weaviateApiKey', credentialData, nodeData)
166278

167-
const clientConfig: any = {
168-
scheme: weaviateScheme,
169-
host: weaviateHost
170-
}
171-
if (weaviateApiKey) clientConfig.apiKey = new ApiKey(weaviateApiKey)
172-
173-
const client: WeaviateClient = weaviate.client(clientConfig)
174-
279+
const client = await createWeaviateClient(
280+
weaviateConnectionType,
281+
weaviateHost,
282+
weaviateHttpSecure,
283+
weaviateGrpcHost,
284+
weaviateGrpcSecure,
285+
weaviateApiKey
286+
)
175287
const flattenDocs = docs && docs.length ? flatten(docs) : []
176288
const finalDocs = []
177289
for (let i = 0; i < flattenDocs.length; i += 1) {
@@ -217,8 +329,11 @@ class Weaviate_VectorStores implements INode {
217329
}
218330
},
219331
async delete(nodeData: INodeData, ids: string[], options: ICommonObject): Promise<void> {
220-
const weaviateScheme = nodeData.inputs?.weaviateScheme as string
221332
const weaviateHost = nodeData.inputs?.weaviateHost as string
333+
const weaviateGrpcHost = nodeData.inputs?.weaviateGrpcHost as string
334+
const weaviateHttpSecure = nodeData.inputs?.weaviateHttpSecure as boolean
335+
const weaviateGrpcSecure = nodeData.inputs?.weaviateGrpcSecure as boolean
336+
const weaviateConnectionType = nodeData.inputs?.weaviateConnectionType as string
222337
const weaviateIndex = nodeData.inputs?.weaviateIndex as string
223338
const weaviateTextKey = nodeData.inputs?.weaviateTextKey as string
224339
const weaviateMetadataKeys = nodeData.inputs?.weaviateMetadataKeys as string
@@ -228,13 +343,14 @@ class Weaviate_VectorStores implements INode {
228343
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
229344
const weaviateApiKey = getCredentialParam('weaviateApiKey', credentialData, nodeData)
230345

231-
const clientConfig: any = {
232-
scheme: weaviateScheme,
233-
host: weaviateHost
234-
}
235-
if (weaviateApiKey) clientConfig.apiKey = new ApiKey(weaviateApiKey)
236-
237-
const client: WeaviateClient = weaviate.client(clientConfig)
346+
const client = await createWeaviateClient(
347+
weaviateConnectionType,
348+
weaviateHost,
349+
weaviateHttpSecure,
350+
weaviateGrpcHost,
351+
weaviateGrpcSecure,
352+
weaviateApiKey
353+
)
238354

239355
const obj: WeaviateLibArgs = {
240356
//@ts-ignore
@@ -270,8 +386,11 @@ class Weaviate_VectorStores implements INode {
270386
}
271387

272388
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
273-
const weaviateScheme = nodeData.inputs?.weaviateScheme as string
274389
const weaviateHost = nodeData.inputs?.weaviateHost as string
390+
const weaviateGrpcHost = nodeData.inputs?.weaviateGrpcHost as string
391+
const weaviateHttpSecure = nodeData.inputs?.weaviateHttpSecure as boolean
392+
const weaviateGrpcSecure = nodeData.inputs?.weaviateGrpcSecure as boolean
393+
const weaviateConnectionType = nodeData.inputs?.weaviateConnectionType as string
275394
const weaviateIndex = nodeData.inputs?.weaviateIndex as string
276395
const weaviateTextKey = nodeData.inputs?.weaviateTextKey as string
277396
const weaviateMetadataKeys = nodeData.inputs?.weaviateMetadataKeys as string
@@ -281,13 +400,14 @@ class Weaviate_VectorStores implements INode {
281400
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
282401
const weaviateApiKey = getCredentialParam('weaviateApiKey', credentialData, nodeData)
283402

284-
const clientConfig: any = {
285-
scheme: weaviateScheme,
286-
host: weaviateHost
287-
}
288-
if (weaviateApiKey) clientConfig.apiKey = new ApiKey(weaviateApiKey)
289-
290-
const client: WeaviateClient = weaviate.client(clientConfig)
403+
const client = await createWeaviateClient(
404+
weaviateConnectionType,
405+
weaviateHost,
406+
weaviateHttpSecure,
407+
weaviateGrpcHost,
408+
weaviateGrpcSecure,
409+
weaviateApiKey
410+
)
291411

292412
const obj: WeaviateLibArgs = {
293413
//@ts-ignore

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171
"supergateway": "3.0.1",
172172
"typeorm": "^0.3.6",
173173
"uuid": "^10.0.0",
174-
"weaviate-ts-client": "^1.1.0",
174+
"weaviate-client": "3.12.0",
175175
"winston": "^3.9.0",
176176
"ws": "^8.18.0",
177177
"xlsx": "0.18.5",

packages/components/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export const availableDependencies = [
118118
'replicate',
119119
'srt-parser-2',
120120
'typeorm',
121-
'weaviate-ts-client'
121+
'weaviate-client'
122122
]
123123

124124
const defaultAllowExternalDependencies = ['axios', 'moment', 'node-fetch']

0 commit comments

Comments
 (0)