@sylphx/flow 1.1.1 → 1.2.0
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.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/commands/hook-command.ts +10 -230
- package/src/composables/index.ts +0 -1
- package/src/config/servers.ts +35 -78
- package/src/core/interfaces.ts +0 -33
- package/src/domains/index.ts +0 -2
- package/src/index.ts +0 -4
- package/src/services/mcp-service.ts +0 -16
- package/src/targets/claude-code.ts +3 -9
- package/src/targets/functional/claude-code-logic.ts +4 -22
- package/src/targets/opencode.ts +0 -6
- package/src/types/mcp.types.ts +29 -38
- package/src/types/target.types.ts +0 -2
- package/src/types.ts +0 -1
- package/src/commands/codebase-command.ts +0 -168
- package/src/commands/knowledge-command.ts +0 -161
- package/src/composables/useTargetConfig.ts +0 -45
- package/src/core/formatting/bytes.test.ts +0 -115
- package/src/core/validation/limit.test.ts +0 -155
- package/src/core/validation/query.test.ts +0 -44
- package/src/domains/codebase/index.ts +0 -5
- package/src/domains/codebase/tools.ts +0 -139
- package/src/domains/knowledge/index.ts +0 -10
- package/src/domains/knowledge/resources.ts +0 -537
- package/src/domains/knowledge/tools.ts +0 -174
- package/src/services/search/base-indexer.ts +0 -156
- package/src/services/search/codebase-indexer-types.ts +0 -38
- package/src/services/search/codebase-indexer.ts +0 -647
- package/src/services/search/embeddings-provider.ts +0 -455
- package/src/services/search/embeddings.ts +0 -316
- package/src/services/search/functional-indexer.ts +0 -323
- package/src/services/search/index.ts +0 -27
- package/src/services/search/indexer.ts +0 -380
- package/src/services/search/knowledge-indexer.ts +0 -422
- package/src/services/search/semantic-search.ts +0 -244
- package/src/services/search/tfidf.ts +0 -559
- package/src/services/search/unified-search-service.ts +0 -888
- package/src/services/storage/cache-storage.ts +0 -487
- package/src/services/storage/drizzle-storage.ts +0 -581
- package/src/services/storage/index.ts +0 -15
- package/src/services/storage/lancedb-vector-storage.ts +0 -494
- package/src/services/storage/memory-storage.ts +0 -268
- package/src/services/storage/separated-storage.ts +0 -467
- package/src/services/storage/vector-storage.ts +0 -13
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embeddings Provider Service - 嵌入向量提供者服務
|
|
3
|
-
* 統一管理所有embedding相關操作
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { type Result, tryCatchAsync } from '../../core/functional/result.js';
|
|
7
|
-
import {
|
|
8
|
-
EmbeddingInitError,
|
|
9
|
-
EmbeddingNotInitializedError,
|
|
10
|
-
type EmbeddingsErrorType,
|
|
11
|
-
VectorDimensionError,
|
|
12
|
-
} from '../../errors/embeddings-errors.js';
|
|
13
|
-
import type { EmbeddingProvider } from '../../utils/embeddings.js';
|
|
14
|
-
import { getDefaultEmbeddingProvider } from '../../utils/embeddings.js';
|
|
15
|
-
import { chunk } from '../../utils/functional/array.js';
|
|
16
|
-
import { createLogger } from '../../utils/debug-logger.js';
|
|
17
|
-
|
|
18
|
-
const log = createLogger('search:embeddings');
|
|
19
|
-
|
|
20
|
-
export interface EmbeddingConfig {
|
|
21
|
-
provider?: 'openai' | 'local' | 'auto';
|
|
22
|
-
model?: string;
|
|
23
|
-
dimensions?: number;
|
|
24
|
-
batchSize?: number;
|
|
25
|
-
maxTokens?: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface EmbeddingResult {
|
|
29
|
-
embeddings: number[][];
|
|
30
|
-
tokensUsed: number;
|
|
31
|
-
processingTime: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Internal state for embeddings provider
|
|
36
|
-
*/
|
|
37
|
-
interface EmbeddingsProviderState {
|
|
38
|
-
readonly provider?: EmbeddingProvider;
|
|
39
|
-
readonly isInitialized: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Embeddings Provider Service Interface
|
|
44
|
-
* 嵌入向量提供者服務
|
|
45
|
-
*/
|
|
46
|
-
export interface EmbeddingsProviderService {
|
|
47
|
-
readonly initialize: () => Promise<Result<void, EmbeddingsErrorType>>;
|
|
48
|
-
readonly generateEmbeddings: (
|
|
49
|
-
texts: string[]
|
|
50
|
-
) => Promise<Result<number[][], EmbeddingsErrorType>>;
|
|
51
|
-
readonly generateEmbedding: (text: string) => Promise<Result<number[], EmbeddingsErrorType>>;
|
|
52
|
-
readonly generateEmbeddingsWithMetrics: (
|
|
53
|
-
texts: string[]
|
|
54
|
-
) => Promise<Result<EmbeddingResult, EmbeddingsErrorType>>;
|
|
55
|
-
readonly isValidText: (text: string) => boolean;
|
|
56
|
-
readonly preprocessText: (text: string) => string;
|
|
57
|
-
readonly preprocessTexts: (texts: string[]) => string[];
|
|
58
|
-
readonly cosineSimilarity: (
|
|
59
|
-
vecA: number[],
|
|
60
|
-
vecB: number[]
|
|
61
|
-
) => Result<number, VectorDimensionError>;
|
|
62
|
-
readonly findMostSimilar: (
|
|
63
|
-
queryVector: number[],
|
|
64
|
-
candidateVectors: number[][]
|
|
65
|
-
) => Result<{ index: number; similarity: number }, VectorDimensionError>;
|
|
66
|
-
readonly getConfig: () => EmbeddingConfig;
|
|
67
|
-
readonly updateConfig: (newConfig: Partial<EmbeddingConfig>) => void;
|
|
68
|
-
readonly getProviderInfo: () => Promise<
|
|
69
|
-
Result<
|
|
70
|
-
{
|
|
71
|
-
provider: string;
|
|
72
|
-
model: string;
|
|
73
|
-
dimensions: number;
|
|
74
|
-
available: boolean;
|
|
75
|
-
},
|
|
76
|
-
EmbeddingsErrorType
|
|
77
|
-
>
|
|
78
|
-
>;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Create embeddings provider service (Factory Function)
|
|
83
|
-
* 提供統一嘅embedding interface和配置管理
|
|
84
|
-
*/
|
|
85
|
-
export const createEmbeddingsProviderService = (
|
|
86
|
-
config: EmbeddingConfig = {}
|
|
87
|
-
): EmbeddingsProviderService => {
|
|
88
|
-
// Immutable config with defaults
|
|
89
|
-
let serviceConfig: EmbeddingConfig = {
|
|
90
|
-
provider: 'auto',
|
|
91
|
-
batchSize: 10,
|
|
92
|
-
maxTokens: 8000,
|
|
93
|
-
dimensions: 1536,
|
|
94
|
-
...config,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// Mutable state in closure (will be updated immutably)
|
|
98
|
-
let state: EmbeddingsProviderState = {
|
|
99
|
-
provider: undefined,
|
|
100
|
-
isInitialized: false,
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// Helper: Update state immutably
|
|
104
|
-
const updateState = (updates: Partial<EmbeddingsProviderState>): void => {
|
|
105
|
-
state = { ...state, ...updates };
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* 初始化embedding provider
|
|
110
|
-
*/
|
|
111
|
-
const initialize = async (): Promise<Result<void, EmbeddingsErrorType>> => {
|
|
112
|
-
if (state.isInitialized) {
|
|
113
|
-
return { _tag: 'Success', value: undefined };
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return await tryCatchAsync(
|
|
117
|
-
async () => {
|
|
118
|
-
const provider = await getDefaultEmbeddingProvider();
|
|
119
|
-
updateState({ provider, isInitialized: true });
|
|
120
|
-
return undefined;
|
|
121
|
-
},
|
|
122
|
-
(error) => new EmbeddingInitError(error)
|
|
123
|
-
);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* 確保已初始化
|
|
128
|
-
*/
|
|
129
|
-
const ensureInitialized = async (): Promise<Result<void, EmbeddingsErrorType>> => {
|
|
130
|
-
if (!state.isInitialized) {
|
|
131
|
-
return await initialize();
|
|
132
|
-
}
|
|
133
|
-
return { _tag: 'Success', value: undefined };
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* 生成嵌入向量
|
|
138
|
-
*/
|
|
139
|
-
const generateEmbeddings = async (
|
|
140
|
-
texts: string[]
|
|
141
|
-
): Promise<Result<number[][], EmbeddingsErrorType>> => {
|
|
142
|
-
return await tryCatchAsync(
|
|
143
|
-
async () => {
|
|
144
|
-
const initResult = await ensureInitialized();
|
|
145
|
-
if (initResult._tag === 'Failure') {
|
|
146
|
-
throw initResult.error;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (!state.provider) {
|
|
150
|
-
throw new EmbeddingNotInitializedError();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 檢查文本長度
|
|
154
|
-
const filteredTexts = texts.filter((text) => text.trim().length > 0);
|
|
155
|
-
if (filteredTexts.length === 0) {
|
|
156
|
-
return [];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// FUNCTIONAL: 批量處理 - Use chunk and flatMap instead of for loop
|
|
160
|
-
const batchSize = serviceConfig.batchSize || 10;
|
|
161
|
-
const batches = chunk(batchSize)(filteredTexts);
|
|
162
|
-
|
|
163
|
-
// Process batches and flatten results
|
|
164
|
-
const batchResults = await Promise.all(
|
|
165
|
-
batches.map(async (batch, index) => {
|
|
166
|
-
try {
|
|
167
|
-
return await state.provider?.generateEmbeddings(batch);
|
|
168
|
-
} catch (error) {
|
|
169
|
-
log(
|
|
170
|
-
`Batch ${index * batchSize}-${index * batchSize + batchSize} failed:`,
|
|
171
|
-
error instanceof Error ? error.message : String(error)
|
|
172
|
-
);
|
|
173
|
-
// 為失敗嘅batch添加零向量
|
|
174
|
-
const zeroVector = new Array(serviceConfig.dimensions || 1536).fill(0);
|
|
175
|
-
return Array(batch.length).fill(zeroVector);
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
return batchResults.flat();
|
|
181
|
-
},
|
|
182
|
-
(error) => {
|
|
183
|
-
if (error instanceof EmbeddingInitError || error instanceof EmbeddingNotInitializedError) {
|
|
184
|
-
return error;
|
|
185
|
-
}
|
|
186
|
-
return new EmbeddingInitError(error);
|
|
187
|
-
}
|
|
188
|
-
);
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* 生成單個文本嘅嵌入向量
|
|
193
|
-
*/
|
|
194
|
-
const generateEmbedding = async (
|
|
195
|
-
text: string
|
|
196
|
-
): Promise<Result<number[], EmbeddingsErrorType>> => {
|
|
197
|
-
return await tryCatchAsync(
|
|
198
|
-
async () => {
|
|
199
|
-
const result = await generateEmbeddings([text]);
|
|
200
|
-
if (result._tag === 'Failure') {
|
|
201
|
-
throw result.error;
|
|
202
|
-
}
|
|
203
|
-
return result.value[0] || [];
|
|
204
|
-
},
|
|
205
|
-
(error) => {
|
|
206
|
-
if (error instanceof EmbeddingInitError || error instanceof EmbeddingNotInitializedError) {
|
|
207
|
-
return error;
|
|
208
|
-
}
|
|
209
|
-
return new EmbeddingInitError(error);
|
|
210
|
-
}
|
|
211
|
-
);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* 批量生成嵌入向量(帶性能監控)
|
|
216
|
-
*/
|
|
217
|
-
const generateEmbeddingsWithMetrics = async (
|
|
218
|
-
texts: string[]
|
|
219
|
-
): Promise<Result<EmbeddingResult, EmbeddingsErrorType>> => {
|
|
220
|
-
return await tryCatchAsync(
|
|
221
|
-
async () => {
|
|
222
|
-
const startTime = Date.now();
|
|
223
|
-
|
|
224
|
-
const result = await generateEmbeddings(texts);
|
|
225
|
-
if (result._tag === 'Failure') {
|
|
226
|
-
throw result.error;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const processingTime = Date.now() - startTime;
|
|
230
|
-
const tokensUsed = estimateTokens(texts);
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
embeddings: result.value,
|
|
234
|
-
tokensUsed,
|
|
235
|
-
processingTime,
|
|
236
|
-
};
|
|
237
|
-
},
|
|
238
|
-
(error) => {
|
|
239
|
-
if (error instanceof EmbeddingInitError || error instanceof EmbeddingNotInitializedError) {
|
|
240
|
-
return error;
|
|
241
|
-
}
|
|
242
|
-
return new EmbeddingInitError(error);
|
|
243
|
-
}
|
|
244
|
-
);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* 估算token數量
|
|
249
|
-
*/
|
|
250
|
-
const estimateTokens = (texts: string[]): number => {
|
|
251
|
-
// 簡單嘅token估算(約4 characters = 1 token)
|
|
252
|
-
const totalChars = texts.reduce((sum, text) => sum + text.length, 0);
|
|
253
|
-
return Math.ceil(totalChars / 4);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* 檢查文本是否適合生成embedding
|
|
258
|
-
*/
|
|
259
|
-
const isValidText = (text: string): boolean => {
|
|
260
|
-
if (!text || typeof text !== 'string') {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const trimmed = text.trim();
|
|
265
|
-
if (trimmed.length === 0) {
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// 檢查長度限制
|
|
270
|
-
const maxTokens = serviceConfig.maxTokens || 8000;
|
|
271
|
-
const estimatedTokens = Math.ceil(trimmed.length / 4);
|
|
272
|
-
|
|
273
|
-
return estimatedTokens <= maxTokens;
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* 預處理文本
|
|
278
|
-
*/
|
|
279
|
-
const preprocessText = (text: string): string => {
|
|
280
|
-
if (!text || typeof text !== 'string') {
|
|
281
|
-
return '';
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return (
|
|
285
|
-
text
|
|
286
|
-
.trim()
|
|
287
|
-
// 移除多餘嘅空白字符
|
|
288
|
-
.replace(/\s+/g, ' ')
|
|
289
|
-
// 截斷過長嘅文本
|
|
290
|
-
.slice(0, (serviceConfig.maxTokens || 8000) * 4)
|
|
291
|
-
);
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* 批量預處理文本
|
|
296
|
-
*/
|
|
297
|
-
const preprocessTexts = (texts: string[]): string[] => {
|
|
298
|
-
return texts.filter((text) => isValidText(text)).map((text) => preprocessText(text));
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* 計算兩個向量嘅餘弦相似度
|
|
303
|
-
*/
|
|
304
|
-
const cosineSimilarity = (
|
|
305
|
-
vecA: number[],
|
|
306
|
-
vecB: number[]
|
|
307
|
-
): Result<number, VectorDimensionError> => {
|
|
308
|
-
if (vecA.length !== vecB.length) {
|
|
309
|
-
return { _tag: 'Failure', error: new VectorDimensionError(vecA.length, vecB.length) };
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// FUNCTIONAL: Use reduce instead of for loop
|
|
313
|
-
const { dotProduct, normA, normB } = vecA.reduce(
|
|
314
|
-
(acc, aVal, i) => {
|
|
315
|
-
const bVal = vecB[i];
|
|
316
|
-
return {
|
|
317
|
-
dotProduct: acc.dotProduct + aVal * bVal,
|
|
318
|
-
normA: acc.normA + aVal * aVal,
|
|
319
|
-
normB: acc.normB + bVal * bVal,
|
|
320
|
-
};
|
|
321
|
-
},
|
|
322
|
-
{ dotProduct: 0, normA: 0, normB: 0 }
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
if (normA === 0 || normB === 0) {
|
|
326
|
-
return { _tag: 'Success', value: 0 };
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return { _tag: 'Success', value: dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)) };
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* 找到最相似嘅向量
|
|
334
|
-
*/
|
|
335
|
-
const findMostSimilar = (
|
|
336
|
-
queryVector: number[],
|
|
337
|
-
candidateVectors: number[][]
|
|
338
|
-
): Result<{ index: number; similarity: number }, VectorDimensionError> => {
|
|
339
|
-
// FUNCTIONAL: Use reduce instead of for loop
|
|
340
|
-
const result = candidateVectors.reduce<
|
|
341
|
-
Result<{ index: number; similarity: number }, VectorDimensionError>
|
|
342
|
-
>(
|
|
343
|
-
(acc, candidateVector, index) => {
|
|
344
|
-
// Short-circuit on error
|
|
345
|
-
if (acc._tag === 'Failure') {
|
|
346
|
-
return acc;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const similarityResult = cosineSimilarity(queryVector, candidateVector);
|
|
350
|
-
if (similarityResult._tag === 'Failure') {
|
|
351
|
-
return similarityResult;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const similarity = similarityResult.value;
|
|
355
|
-
return similarity > acc.value.similarity
|
|
356
|
-
? { _tag: 'Success', value: { index, similarity } }
|
|
357
|
-
: acc;
|
|
358
|
-
},
|
|
359
|
-
{ _tag: 'Success', value: { index: -1, similarity: 0 } }
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
return result;
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* 獲取配置信息
|
|
367
|
-
*/
|
|
368
|
-
const getConfig = (): EmbeddingConfig => {
|
|
369
|
-
return { ...serviceConfig };
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* 更新配置
|
|
374
|
-
*/
|
|
375
|
-
const updateConfig = (newConfig: Partial<EmbeddingConfig>): void => {
|
|
376
|
-
serviceConfig = { ...serviceConfig, ...newConfig };
|
|
377
|
-
|
|
378
|
-
// 如果provider相關配置改變,需要重新初始化
|
|
379
|
-
if (newConfig.provider || newConfig.model) {
|
|
380
|
-
updateState({ isInitialized: false });
|
|
381
|
-
}
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* 獲取provider信息
|
|
386
|
-
*/
|
|
387
|
-
const getProviderInfo = async (): Promise<
|
|
388
|
-
Result<
|
|
389
|
-
{
|
|
390
|
-
provider: string;
|
|
391
|
-
model: string;
|
|
392
|
-
dimensions: number;
|
|
393
|
-
available: boolean;
|
|
394
|
-
},
|
|
395
|
-
EmbeddingsErrorType
|
|
396
|
-
>
|
|
397
|
-
> => {
|
|
398
|
-
return await tryCatchAsync(
|
|
399
|
-
async () => {
|
|
400
|
-
const initResult = await ensureInitialized();
|
|
401
|
-
if (initResult._tag === 'Failure') {
|
|
402
|
-
// Return unavailable info instead of throwing
|
|
403
|
-
return {
|
|
404
|
-
provider: serviceConfig.provider || 'unknown',
|
|
405
|
-
model: serviceConfig.model || 'unknown',
|
|
406
|
-
dimensions: serviceConfig.dimensions || 1536,
|
|
407
|
-
available: false,
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (!state.provider) {
|
|
412
|
-
return {
|
|
413
|
-
provider: serviceConfig.provider || 'unknown',
|
|
414
|
-
model: serviceConfig.model || 'unknown',
|
|
415
|
-
dimensions: serviceConfig.dimensions || 1536,
|
|
416
|
-
available: false,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// 這裡需要根據實際provider interface實現
|
|
421
|
-
return {
|
|
422
|
-
provider: serviceConfig.provider || 'unknown',
|
|
423
|
-
model: serviceConfig.model || 'unknown',
|
|
424
|
-
dimensions: serviceConfig.dimensions || 1536,
|
|
425
|
-
available: true,
|
|
426
|
-
};
|
|
427
|
-
},
|
|
428
|
-
(error) => new EmbeddingInitError(error)
|
|
429
|
-
);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
// Return service interface
|
|
433
|
-
return {
|
|
434
|
-
initialize,
|
|
435
|
-
generateEmbeddings,
|
|
436
|
-
generateEmbedding,
|
|
437
|
-
generateEmbeddingsWithMetrics,
|
|
438
|
-
isValidText,
|
|
439
|
-
preprocessText,
|
|
440
|
-
preprocessTexts,
|
|
441
|
-
cosineSimilarity,
|
|
442
|
-
findMostSimilar,
|
|
443
|
-
getConfig,
|
|
444
|
-
updateConfig,
|
|
445
|
-
getProviderInfo,
|
|
446
|
-
};
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
// 預設實例 - Use factory function
|
|
450
|
-
export const defaultEmbeddingsProvider = createEmbeddingsProviderService();
|
|
451
|
-
|
|
452
|
-
// 工廠函數別名 - For backwards compatibility
|
|
453
|
-
export function createEmbeddingsProvider(config?: EmbeddingConfig): EmbeddingsProviderService {
|
|
454
|
-
return createEmbeddingsProviderService(config);
|
|
455
|
-
}
|