@vfarcic/dot-ai 0.194.0 → 0.194.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"mermaid-tools.d.ts","sourceRoot":"","sources":["../../src/core/mermaid-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAWjD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,MA0BnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,EAEjC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,GAAG,GACT,OAAO,CAAC,GAAG,CAAC,CAoDd"}
1
+ {"version":3,"file":"mermaid-tools.d.ts","sourceRoot":"","sources":["../../src/core/mermaid-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AASjD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,MA0BnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,EAEjC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,GAAG,GACT,OAAO,CAAC,GAAG,CAAC,CAoDd"}
@@ -17,9 +17,7 @@ const mermaid_1 = __importDefault(require("mermaid"));
17
17
  // Initialize mermaid with strict validation
18
18
  mermaid_1.default.initialize({
19
19
  securityLevel: 'strict',
20
- startOnLoad: false,
21
- // Disable rendering, we only want parsing/validation
22
- suppressErrorRendering: true
20
+ startOnLoad: false
23
21
  });
24
22
  /**
25
23
  * Tool: validate_mermaid
@@ -43,6 +43,11 @@ export declare class VectorDBService {
43
43
  * Handles conflict errors gracefully (collection already exists from race condition or restart)
44
44
  */
45
45
  private createCollection;
46
+ /**
47
+ * Ensure text index exists on searchText field for efficient keyword search
48
+ * This is idempotent - safe to call multiple times
49
+ */
50
+ private ensureTextIndex;
46
51
  /**
47
52
  * Store a document with optional vector
48
53
  */
@@ -53,6 +58,7 @@ export declare class VectorDBService {
53
58
  searchSimilar(vector: number[], options?: SearchOptions): Promise<SearchResult[]>;
54
59
  /**
55
60
  * Search for documents using payload filtering (keyword search)
61
+ * Uses Qdrant's native text index for efficient server-side filtering
56
62
  */
57
63
  searchByKeywords(keywords: string[], options?: SearchOptions): Promise<SearchResult[]>;
58
64
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"vector-db-service.d.ts","sourceRoot":"","sources":["../../src/core/vector-db-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgDH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,GAAE,cAAmB;IAsBvC,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,sBAAsB;IAM9B;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAa1C;;OAEG;IACG,oBAAoB,CAAC,UAAU,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDnE;;;OAGG;YACW,gBAAgB;IAgC9B;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC7D;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC;IAuC1B;;OAEG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC;IA0F1B;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqC7D;;OAEG;IACG,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/C;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCzC;;;;;OAKG;IACG,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,GAAE,MAAY,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAuCnF;;;;OAIG;IACG,eAAe,CAAC,KAAK,GAAE,MAAc,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgDvE;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC;IAqBvC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAsBrC;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,SAAS,IAAI,cAAc;CAG5B"}
1
+ {"version":3,"file":"vector-db-service.d.ts","sourceRoot":"","sources":["../../src/core/vector-db-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgDH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,GAAE,cAAmB;IAuBvC,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,sBAAsB;IAM9B;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAa1C;;OAEG;IACG,oBAAoB,CAAC,UAAU,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDnE;;;OAGG;YACW,gBAAgB;IAmC9B;;;OAGG;YACW,eAAe;IAwC7B;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC7D;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC;IAuC1B;;;OAGG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC;IA8H1B;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqC7D;;OAEG;IACG,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/C;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCzC;;;;;OAKG;IACG,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,GAAE,MAAY,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAuCnF;;;;OAIG;IACG,eAAe,CAAC,KAAK,GAAE,MAAc,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgDvE;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC;IAqBvC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAsBrC;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,SAAS,IAAI,cAAc;CAG5B"}
@@ -44,8 +44,8 @@ class QdrantSemaphore {
44
44
  }
45
45
  }
46
46
  }
47
- // Limit to 20 concurrent Qdrant operations
48
- const qdrantSemaphore = new QdrantSemaphore(20);
47
+ // Limit concurrent Qdrant bulk operations (scroll, getAllDocuments)
48
+ const qdrantSemaphore = new QdrantSemaphore(100);
49
49
  class VectorDBService {
50
50
  client = null;
51
51
  config;
@@ -64,7 +64,8 @@ class VectorDBService {
64
64
  if (this.shouldInitializeClient()) {
65
65
  this.client = new js_client_rest_1.QdrantClient({
66
66
  url: this.config.url,
67
- apiKey: this.config.apiKey
67
+ apiKey: this.config.apiKey,
68
+ maxConnections: 100, // HTTP keep-alive pool for connection reuse
68
69
  });
69
70
  }
70
71
  }
@@ -125,6 +126,10 @@ class VectorDBService {
125
126
  await this.client.deleteCollection(this.collectionName);
126
127
  await this.createCollection(vectorSize);
127
128
  }
129
+ else {
130
+ // Ensure text index exists for existing collections (transparent upgrade)
131
+ await this.ensureTextIndex();
132
+ }
128
133
  }
129
134
  catch (error) {
130
135
  // If we can't get collection info, assume it's corrupted and recreate
@@ -158,11 +163,12 @@ class VectorDBService {
158
163
  distance: 'Cosine',
159
164
  on_disk: true // Enable on-disk storage for better performance with large collections
160
165
  },
161
- // Enable payload indexing for better keyword search performance
162
166
  optimizers_config: {
163
167
  default_segment_number: 2
164
168
  }
165
169
  });
170
+ // Create text index on searchText field for efficient keyword search
171
+ await this.ensureTextIndex();
166
172
  }
167
173
  catch (error) {
168
174
  // Handle race condition where collection was created between check and create
@@ -173,11 +179,53 @@ class VectorDBService {
173
179
  if (process.env.DEBUG_DOT_AI) {
174
180
  console.debug(`Collection ${this.collectionName} already exists, skipping creation`);
175
181
  }
182
+ await this.ensureTextIndex();
176
183
  return;
177
184
  }
178
185
  throw error;
179
186
  }
180
187
  }
188
+ /**
189
+ * Ensure text index exists on searchText field for efficient keyword search
190
+ * This is idempotent - safe to call multiple times
191
+ */
192
+ async ensureTextIndex() {
193
+ if (!this.client) {
194
+ return;
195
+ }
196
+ try {
197
+ // Check if index already exists
198
+ const collectionInfo = await this.client.getCollection(this.collectionName);
199
+ const payloadSchema = collectionInfo.payload_schema || {};
200
+ // Check if searchText already has a text index
201
+ const searchTextIndex = payloadSchema['searchText'];
202
+ if (searchTextIndex && searchTextIndex.data_type === 'text') {
203
+ return; // Index already exists
204
+ }
205
+ // Create text index on searchText field
206
+ await this.client.createPayloadIndex(this.collectionName, {
207
+ field_name: 'searchText',
208
+ field_schema: 'text',
209
+ });
210
+ if (process.env.DEBUG_DOT_AI) {
211
+ console.debug(`Created text index on searchText field for collection ${this.collectionName}`);
212
+ }
213
+ }
214
+ catch (error) {
215
+ const errorMessage = error instanceof Error ? error.message : String(error);
216
+ const isAlreadyExists = errorMessage.toLowerCase().includes('already exists') ||
217
+ errorMessage.toLowerCase().includes('conflict');
218
+ if (isAlreadyExists) {
219
+ if (process.env.DEBUG_DOT_AI) {
220
+ console.debug(`Text index already exists for collection ${this.collectionName}`);
221
+ }
222
+ }
223
+ else {
224
+ // Unexpected error - log at warn level for visibility
225
+ console.warn(`Failed to create text index on ${this.collectionName}: ${errorMessage}`);
226
+ }
227
+ }
228
+ }
181
229
  /**
182
230
  * Store a document with optional vector
183
231
  */
@@ -250,12 +298,16 @@ class VectorDBService {
250
298
  }
251
299
  /**
252
300
  * Search for documents using payload filtering (keyword search)
301
+ * Uses Qdrant's native text index for efficient server-side filtering
253
302
  */
254
303
  async searchByKeywords(keywords, options = {}) {
255
304
  if (!this.client) {
256
305
  throw new Error('Vector DB client not initialized');
257
306
  }
258
307
  const limit = options.limit || 10;
308
+ if (keywords.length === 0) {
309
+ return [];
310
+ }
259
311
  return (0, qdrant_tracing_1.withQdrantTracing)({
260
312
  operation: 'vector.search_keywords',
261
313
  collectionName: this.collectionName,
@@ -264,15 +316,50 @@ class VectorDBService {
264
316
  serverUrl: this.config.url
265
317
  }, async () => {
266
318
  try {
267
- // Fallback to JavaScript-based filtering due to Qdrant filter syntax issues
268
- // Get all documents and filter in JavaScript for keyword matching
319
+ // Build Qdrant filter for text search
320
+ // Use "should" (OR) to match any keyword in searchText or triggers
321
+ const keywordConditions = [];
322
+ for (const keyword of keywords) {
323
+ // Text match on searchText field (uses text index)
324
+ keywordConditions.push({
325
+ key: 'searchText',
326
+ match: { text: keyword }
327
+ });
328
+ // Match on triggers array (for patterns/policies)
329
+ keywordConditions.push({
330
+ key: 'triggers',
331
+ match: { any: [keyword, keyword.toLowerCase()] }
332
+ });
333
+ }
334
+ // Combine keyword conditions with any user-provided filter
335
+ const filter = {
336
+ should: keywordConditions
337
+ };
338
+ // If user provided additional filters, merge them properly
339
+ if (options.filter) {
340
+ // Merge must conditions
341
+ if (options.filter.must) {
342
+ filter.must = Array.isArray(options.filter.must)
343
+ ? options.filter.must
344
+ : [options.filter.must];
345
+ }
346
+ // Preserve must_not conditions
347
+ if (options.filter.must_not) {
348
+ filter.must_not = options.filter.must_not;
349
+ }
350
+ // If user filter has should conditions, wrap in must to AND with keyword should
351
+ if (options.filter.should) {
352
+ filter.must = [...(filter.must || []), { should: options.filter.should }];
353
+ }
354
+ }
355
+ // Use scroll with native Qdrant filtering - much faster than client-side
269
356
  const scrollResult = await this.client.scroll(this.collectionName, {
270
- limit: 1000, // Get all documents for filtering
357
+ limit: limit * 10, // Get more candidates for scoring, but not 1000
271
358
  with_payload: true,
272
359
  with_vector: false,
273
- ...(options.filter && { filter: options.filter })
360
+ filter
274
361
  });
275
- // Filter documents by checking if any keyword matches searchText or triggers
362
+ // Score the filtered results (small set now)
276
363
  const scoredPoints = scrollResult.points
277
364
  .map(point => {
278
365
  if (!point.payload)
@@ -286,35 +373,27 @@ class VectorDBService {
286
373
  let exactMatch = false;
287
374
  for (const keyword of keywords) {
288
375
  const kw = keyword.toLowerCase();
289
- // Check searchText (name, kind, namespace, labels, etc.)
376
+ // Check searchText
290
377
  if (searchText.includes(kw)) {
291
378
  matchCount++;
292
- // Bonus for exact word match (surrounded by spaces/punctuation)
293
379
  const wordPattern = new RegExp(`\\b${escapeRegExp(kw)}\\b`, 'i');
294
380
  if (wordPattern.test(searchText)) {
295
381
  exactMatch = true;
296
382
  }
297
383
  }
298
- // Check triggers (for patterns/policies)
384
+ // Check triggers
299
385
  if (triggers.some(t => t.includes(kw) || kw.includes(t))) {
300
386
  matchCount++;
301
387
  }
302
388
  }
303
389
  if (matchCount === 0)
304
390
  return null;
305
- // Score based on match quality
306
- // - Base score from match ratio
307
- // - Bonus for exact word matches
308
391
  const baseScore = matchCount / keywords.length;
309
392
  const score = exactMatch ? Math.min(1.0, baseScore + 0.3) : baseScore;
310
- return {
311
- point,
312
- score
313
- };
393
+ return { point, score };
314
394
  })
315
395
  .filter((item) => item !== null)
316
396
  .sort((a, b) => b.score - a.score);
317
- // Apply limit after filtering
318
397
  const limitedResults = scoredPoints.slice(0, limit);
319
398
  return limitedResults.map(({ point, score }) => ({
320
399
  id: point.id.toString(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vfarcic/dot-ai",
3
- "version": "0.194.0",
3
+ "version": "0.194.1",
4
4
  "description": "AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance",
5
5
  "mcpName": "io.github.vfarcic/dot-ai",
6
6
  "main": "dist/index.js",
@@ -114,7 +114,7 @@
114
114
  "@qdrant/js-client-rest": "^1.15.0",
115
115
  "ai": "^5.0.60",
116
116
  "handlebars": "^4.7.8",
117
- "mermaid": "^11.12.2",
117
+ "mermaid": "^10.9.5",
118
118
  "posthog-node": "^5.23.0",
119
119
  "yaml": "^2.8.0",
120
120
  "zod-to-json-schema": "^3.24.6"