agentlang 0.9.6 → 0.9.8

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.
Files changed (78) hide show
  1. package/out/cli/main.d.ts.map +1 -1
  2. package/out/cli/main.js +8 -3
  3. package/out/cli/main.js.map +1 -1
  4. package/out/extension/main.cjs +250 -250
  5. package/out/extension/main.cjs.map +2 -2
  6. package/out/language/generated/ast.js +1 -0
  7. package/out/language/generated/ast.js.map +1 -1
  8. package/out/language/main.cjs +2420 -776
  9. package/out/language/main.cjs.map +4 -4
  10. package/out/runtime/docs.d.ts.map +1 -1
  11. package/out/runtime/docs.js +109 -7
  12. package/out/runtime/docs.js.map +1 -1
  13. package/out/runtime/embeddings/chunker.d.ts +9 -0
  14. package/out/runtime/embeddings/chunker.d.ts.map +1 -0
  15. package/out/runtime/embeddings/chunker.js +41 -0
  16. package/out/runtime/embeddings/chunker.js.map +1 -0
  17. package/out/runtime/embeddings/index.d.ts +6 -0
  18. package/out/runtime/embeddings/index.d.ts.map +1 -0
  19. package/out/runtime/embeddings/index.js +6 -0
  20. package/out/runtime/embeddings/index.js.map +1 -0
  21. package/out/runtime/embeddings/openai.d.ts +15 -0
  22. package/out/runtime/embeddings/openai.d.ts.map +1 -0
  23. package/out/runtime/embeddings/openai.js +34 -0
  24. package/out/runtime/embeddings/openai.js.map +1 -0
  25. package/out/runtime/embeddings/provider.d.ts +20 -0
  26. package/out/runtime/embeddings/provider.d.ts.map +1 -0
  27. package/out/runtime/embeddings/provider.js +17 -0
  28. package/out/runtime/embeddings/provider.js.map +1 -0
  29. package/out/runtime/embeddings/registry.d.ts +3 -0
  30. package/out/runtime/embeddings/registry.d.ts.map +1 -0
  31. package/out/runtime/embeddings/registry.js +16 -0
  32. package/out/runtime/embeddings/registry.js.map +1 -0
  33. package/out/runtime/interpreter.d.ts.map +1 -1
  34. package/out/runtime/interpreter.js +8 -4
  35. package/out/runtime/interpreter.js.map +1 -1
  36. package/out/runtime/module.d.ts +24 -2
  37. package/out/runtime/module.d.ts.map +1 -1
  38. package/out/runtime/module.js +94 -7
  39. package/out/runtime/module.js.map +1 -1
  40. package/out/runtime/modules/ai.d.ts +2 -0
  41. package/out/runtime/modules/ai.d.ts.map +1 -1
  42. package/out/runtime/modules/ai.js +81 -18
  43. package/out/runtime/modules/ai.js.map +1 -1
  44. package/out/runtime/resolvers/sqldb/database.d.ts +1 -1
  45. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  46. package/out/runtime/resolvers/sqldb/database.js +177 -51
  47. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  48. package/out/runtime/resolvers/sqldb/impl.d.ts +21 -1
  49. package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
  50. package/out/runtime/resolvers/sqldb/impl.js +176 -45
  51. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  52. package/package.json +188 -185
  53. package/public/pdf.worker.mjs +65152 -0
  54. package/src/cli/main.ts +7 -2
  55. package/src/language/generated/ast.ts +1 -1
  56. package/src/runtime/docs.ts +120 -9
  57. package/src/runtime/embeddings/chunker.ts +50 -0
  58. package/src/runtime/embeddings/index.ts +5 -0
  59. package/src/runtime/embeddings/openai.ts +49 -0
  60. package/src/runtime/embeddings/provider.ts +37 -0
  61. package/src/runtime/embeddings/registry.ts +17 -0
  62. package/src/runtime/interpreter.ts +16 -12
  63. package/src/runtime/module.ts +148 -40
  64. package/src/runtime/modules/ai.ts +100 -20
  65. package/src/runtime/resolvers/sqldb/database.ts +190 -59
  66. package/src/runtime/resolvers/sqldb/impl.ts +235 -58
  67. package/out/setupClassic.d.ts +0 -98
  68. package/out/setupClassic.d.ts.map +0 -1
  69. package/out/setupClassic.js +0 -38
  70. package/out/setupClassic.js.map +0 -1
  71. package/out/setupCommon.d.ts +0 -2
  72. package/out/setupCommon.d.ts.map +0 -1
  73. package/out/setupCommon.js +0 -33
  74. package/out/setupCommon.js.map +0 -1
  75. package/out/setupExtended.d.ts +0 -40
  76. package/out/setupExtended.d.ts.map +0 -1
  77. package/out/setupExtended.js +0 -67
  78. package/out/setupExtended.js.map +0 -1
@@ -31,6 +31,7 @@ import {
31
31
  newInstanceAttributes,
32
32
  Record,
33
33
  Retry,
34
+ resolveDocumentAliases,
34
35
  } from '../module.js';
35
36
  import { provider } from '../agents/registry.js';
36
37
  import {
@@ -60,7 +61,6 @@ import {
60
61
  newAgentScenario,
61
62
  PlannerInstructions,
62
63
  } from '../agents/common.js';
63
- import { PathAttributeNameQuery } from '../defs.js';
64
64
  import { logger } from '../logger.js';
65
65
  import { FlowStep } from '../agents/flows.js';
66
66
  import Handlebars from 'handlebars';
@@ -74,6 +74,27 @@ export const AgentLearnerType = 'learner';
74
74
 
75
75
  const AgentEvalType = 'eval';
76
76
 
77
+ function buildEmbeddingConfig(): object {
78
+ const config: any = {
79
+ provider: process.env.AGENTLANG_EMBEDDING_PROVIDER || 'openai',
80
+ model: process.env.AGENTLANG_EMBEDDING_MODEL || 'text-embedding-3-small',
81
+ chunkSize: 1000,
82
+ chunkOverlap: 200,
83
+ };
84
+
85
+ if (process.env.AGENTLANG_EMBEDDING_CHUNKSIZE) {
86
+ config.chunkSize = parseInt(process.env.AGENTLANG_EMBEDDING_CHUNKSIZE, 1000);
87
+ }
88
+
89
+ if (process.env.AGENTLANG_EMBEDDING_CHUNKOVERLAP) {
90
+ config.chunkOverlap = parseInt(process.env.AGENTLANG_EMBEDDING_CHUNKOVERLAP, 200);
91
+ }
92
+
93
+ return config;
94
+ }
95
+
96
+ const embeddingConfig = JSON.stringify(buildEmbeddingConfig());
97
+
77
98
  export default `module ${CoreAIModuleName}
78
99
 
79
100
  import "./modules/ai.js" @as ai
@@ -117,7 +138,7 @@ workflow saveAgentChatSession {
117
138
  entity Document {
118
139
  title String @id,
119
140
  content String,
120
- @meta {"fullTextSearch": "*"}
141
+ @meta {"fullTextSearch": "*", "embeddingConfig": ${embeddingConfig}}
121
142
  }
122
143
 
123
144
  event doc {
@@ -980,34 +1001,93 @@ Only return a pure JSON object with no extra text, annotations etc.`;
980
1001
 
981
1002
  private async maybeAddRelevantDocuments(message: string, env: Environment): Promise<string> {
982
1003
  if (this.documents && this.documents.length > 0) {
983
- const s = `${message}. Relevant documents are: ${this.documents}`;
984
- const result: any[] = await parseHelper(`{${CoreAIModuleName}/Document? "${s}"}`, env);
985
- if (result && result.length > 0) {
986
- const docs: Instance[] = [];
987
- for (let i = 0; i < result.length; ++i) {
988
- const v: any = result[i];
989
- const r: Instance[] = await parseHelper(
990
- `{${CoreAIModuleName}/Document {${PathAttributeNameQuery} "${v.id}"}}`,
1004
+ try {
1005
+ const docNames = this.documents.split(',').map(d => d.trim());
1006
+ const docTitles = resolveDocumentAliases(docNames);
1007
+
1008
+ const searchQuery = message;
1009
+
1010
+ try {
1011
+ const semanticResult: any[] = await parseHelper(
1012
+ `{${CoreAIModuleName}/Document {content? "${searchQuery.replace(/"/g, '\\"')}"}}`,
991
1013
  env
992
1014
  );
993
- if (r && r.length > 0) {
994
- docs.push(r[0]);
1015
+
1016
+ if (semanticResult && semanticResult.length > 0) {
1017
+ const docs: Instance[] = [];
1018
+ for (const doc of semanticResult) {
1019
+ const docTitle = doc.lookup ? doc.lookup('title') : doc.title;
1020
+ if (AgentInstance.docTitlesMatch(docTitle, docTitles)) {
1021
+ docs.push(
1022
+ doc instanceof Instance
1023
+ ? doc
1024
+ : Instance.newWithAttributes(doc, new Map(Object.entries(doc)))
1025
+ );
1026
+ }
1027
+ }
1028
+
1029
+ if (docs.length > 0) {
1030
+ return message.concat('\n\nRelevant context from documents:\n').concat(
1031
+ docs
1032
+ .map((v: Instance) => {
1033
+ return `Document: ${v.lookup('title')}\n${v.lookup('content') as string}`;
1034
+ })
1035
+ .join('\n\n---\n\n')
1036
+ );
1037
+ }
995
1038
  }
996
- }
997
- if (docs.length > 0) {
998
- message = message.concat('\nUse the additional information given below:\n').concat(
999
- docs
1000
- .map((v: Instance) => {
1001
- return v.lookup('content');
1002
- })
1003
- .join('\n')
1039
+ } catch (semanticErr) {
1040
+ logger.debug(
1041
+ `Semantic search is not available, falling back to title-based filtering: ${semanticErr}`
1004
1042
  );
1005
1043
  }
1044
+
1045
+ const result: any[] = await parseHelper(`{${CoreAIModuleName}/Document? {}}`, env);
1046
+ if (result && result.length > 0) {
1047
+ const docs: Instance[] = [];
1048
+ for (let i = 0; i < result.length; ++i) {
1049
+ const v: any = result[i];
1050
+ const docTitle: string | undefined = AgentInstance.getDocumentTitle(v);
1051
+
1052
+ if (docTitle && docTitles.includes(docTitle)) {
1053
+ if (v instanceof Instance) {
1054
+ docs.push(v);
1055
+ }
1056
+ }
1057
+ }
1058
+
1059
+ if (docs.length > 0) {
1060
+ return message.concat('\n\nRelevant context from documents:\n').concat(
1061
+ docs
1062
+ .map((v: Instance) => {
1063
+ return v.lookup('content') as string;
1064
+ })
1065
+ .join('\n\n')
1066
+ );
1067
+ }
1068
+ }
1069
+ } catch (err) {
1070
+ logger.debug(`Error retrieving documents: ${err}`);
1006
1071
  }
1007
1072
  }
1008
1073
  return message;
1009
1074
  }
1010
1075
 
1076
+ private static docTitlesMatch(title: string | undefined, docNames: string[]): boolean {
1077
+ return title !== undefined && docNames.includes(title);
1078
+ }
1079
+
1080
+ private static getDocumentTitle(doc: any): string | undefined {
1081
+ if (typeof doc.lookup === 'function') {
1082
+ return doc.lookup('title') as string | undefined;
1083
+ } else if (doc.attributes) {
1084
+ return doc.attributes.get('title') as string | undefined;
1085
+ } else if (doc.title) {
1086
+ return doc.title;
1087
+ }
1088
+ return undefined;
1089
+ }
1090
+
1011
1091
  private static ToolsCache = new Map<string, string>();
1012
1092
 
1013
1093
  private toolsAsString(): string {
@@ -49,6 +49,67 @@ import { AppConfig } from '../../state.js';
49
49
 
50
50
  export let defaultDataSource: DataSource | undefined;
51
51
 
52
+ // Detect browser environment
53
+ function isBrowser(): boolean {
54
+ // window for DOM pages, self+importScripts for web workers
55
+ return (
56
+ (typeof window !== 'undefined' && typeof (window as any).document !== 'undefined') ||
57
+ (typeof self !== 'undefined' && typeof (self as any).importScripts === 'function')
58
+ );
59
+ }
60
+
61
+ // SQLite WASM with built-in sqlite-vec for browsers
62
+ // Loaded from CDN - this has sqlite-vec statically compiled in
63
+ let sqliteVecWasmModule: any = null;
64
+
65
+ async function loadSqliteVecWasm(): Promise<any> {
66
+ if (sqliteVecWasmModule) {
67
+ return sqliteVecWasmModule;
68
+ }
69
+
70
+ try {
71
+ // Use dynamic import with string to prevent bundlers from analyzing
72
+ const cdnUrl = 'https://cdn.jsdelivr.net/npm/sqlite-vec-wasm-demo@latest/sqlite3.mjs';
73
+ const module = await import(/* @vite-ignore */ cdnUrl);
74
+ sqliteVecWasmModule = await module.default();
75
+ return sqliteVecWasmModule;
76
+ } catch (err) {
77
+ logger.warn('Failed to load sqlite-vec WASM:', err);
78
+ return null;
79
+ }
80
+ }
81
+
82
+ // Helper to load sqlite-vec based on environment
83
+ async function loadSqliteVec(): Promise<any> {
84
+ // In browser, use WASM version with built-in sqlite-vec
85
+ // In Node.js, use the npm package
86
+ if (isBrowser()) {
87
+ const wasmModule = await loadSqliteVecWasm();
88
+ if (wasmModule) {
89
+ // WASM version has sqlite-vec built-in, no need to call load()
90
+ // Return a compatible interface
91
+ return {
92
+ load: () => {
93
+ // No-op: sqlite-vec is already loaded in WASM version
94
+ logger.info('sqlite-vec WASM loaded (built-in)');
95
+ },
96
+ // Expose the WASM module for direct use if needed
97
+ _wasmModule: wasmModule,
98
+ };
99
+ }
100
+ return null;
101
+ }
102
+
103
+ // Node.js: use npm package
104
+ try {
105
+ // Use variable to prevent bundlers from statically analyzing this import
106
+ const moduleName = 'sqlite-vec';
107
+ return await import(/* @vite-ignore */ moduleName);
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
112
+
52
113
  export class DbContext {
53
114
  txnId: string | undefined;
54
115
  authInfo: ResolverAuthInfo;
@@ -228,9 +289,10 @@ function makeSqliteDataSource(
228
289
  ): DataSource {
229
290
  const synchronize = needSync();
230
291
  //const runMigrations = isRuntimeMode_migration() || isRuntimeMode_undo_migration() || !synchronize;
231
- return new DataSource({
292
+ const dbPath = config?.dbname || mkDbName();
293
+ const ds = new DataSource({
232
294
  type: 'better-sqlite3',
233
- database: config?.dbname || mkDbName(),
295
+ database: dbPath,
234
296
  synchronize: synchronize,
235
297
  entities: entities,
236
298
  migrationsRun: false,
@@ -240,6 +302,25 @@ function makeSqliteDataSource(
240
302
  undefined: 'ignore',
241
303
  },
242
304
  });
305
+ const originalInit = ds.initialize.bind(ds);
306
+ ds.initialize = async () => {
307
+ const res = await originalInit();
308
+ try {
309
+ const sqliteVec = await loadSqliteVec();
310
+ const driver = ds.driver as any;
311
+ const db = driver.databaseConnection || driver.nativeDatabase;
312
+ if (db && sqliteVec?.load) {
313
+ sqliteVec.load(db);
314
+ logger.info('sqlite-vec extension loaded successfully');
315
+ }
316
+ } catch (err: any) {
317
+ logger.warn(
318
+ `Failed to load sqlite-vec extension: ${err.message}. Vector operations may not be available.`
319
+ );
320
+ }
321
+ return res;
322
+ };
323
+ return ds;
243
324
  }
244
325
 
245
326
  async function execMigrationSql(dataSource: DataSource, sql: string[]) {
@@ -283,14 +364,6 @@ async function maybeHandleMigrations(dataSource: DataSource) {
283
364
  }
284
365
  }
285
366
 
286
- function isBrowser(): boolean {
287
- // window for DOM pages, self+importScripts for web workers
288
- return (
289
- (typeof window !== 'undefined' && typeof (window as any).document !== 'undefined') ||
290
- (typeof self !== 'undefined' && typeof (self as any).importScripts === 'function')
291
- );
292
- }
293
-
294
367
  function defaultLocateFile(file: string): string {
295
368
  // Out-of-the-box: use the official CDN in browsers.
296
369
  if (isBrowser()) {
@@ -371,9 +444,14 @@ export function isUsingSqljs(): boolean {
371
444
  return getDbType(AppConfig?.store) == 'sqljs';
372
445
  }
373
446
 
374
- export function isVectorStoreSupported(): boolean {
375
- // Only Postgres supports pgvector
376
- return getDbType(AppConfig?.store) === 'postgres';
447
+ export async function isVectorStoreSupported(): Promise<boolean> {
448
+ const dbType = getDbType(AppConfig?.store);
449
+ if (dbType === 'postgres') return true;
450
+ if (dbType === 'sqlite') {
451
+ const sqliteVecModule = await loadSqliteVec();
452
+ return !!sqliteVecModule;
453
+ }
454
+ return false;
377
455
  }
378
456
 
379
457
  export async function initDatabase(config: DatabaseConfig | undefined) {
@@ -442,50 +520,69 @@ export async function addRowForFullTextSearch(
442
520
  vect: number[],
443
521
  ctx: DbContext
444
522
  ) {
445
- if (!isVectorStoreSupported()) return;
523
+ if (!(await isVectorStoreSupported())) return;
446
524
  try {
447
525
  const vecTableName = tableName + VectorSuffix;
448
526
  const qb = getDatasourceForTransaction(ctx.txnId).createQueryBuilder();
449
527
  const tenantId = await ctx.getTenantId();
450
- const { default: pgvector } = await import('pgvector');
451
- await qb
452
- .insert()
453
- .into(vecTableName)
454
- .values([{ id: id, embedding: pgvector.toSql(vect), __tenant__: tenantId }])
455
- .execute();
528
+ const dbType = getDbType(AppConfig?.store);
529
+ if (dbType === 'postgres') {
530
+ const { default: pgvector } = await import('pgvector');
531
+ await qb
532
+ .insert()
533
+ .into(vecTableName)
534
+ .values([{ id: id, embedding: pgvector.toSql(vect), __tenant__: tenantId }])
535
+ .execute();
536
+ } else {
537
+ await qb
538
+ .insert()
539
+ .into(vecTableName)
540
+ .values([{ id: id, embedding: new Float32Array(vect) }])
541
+ .execute();
542
+ }
456
543
  } catch (err: any) {
457
544
  logger.error(`Failed to add row to vector store - ${err}`);
458
545
  }
459
546
  }
460
547
 
461
548
  export async function initVectorStore(tableNames: string[], ctx: DbContext) {
462
- if (!isVectorStoreSupported()) {
549
+ if (!(await isVectorStoreSupported())) {
463
550
  logger.info(`Vector store not supported for ${getDbType(AppConfig?.store)}, skipping init...`);
464
551
  return;
465
552
  }
553
+ const dbType = getDbType(AppConfig?.store);
466
554
  let notInited = true;
467
- tableNames.forEach(async (vecTableName: string) => {
555
+ for (const vecTableName of tableNames) {
468
556
  const vecRepo = getDatasourceForTransaction(ctx.txnId).getRepository(vecTableName);
469
- if (notInited) {
470
- let failure = false;
471
- try {
472
- await vecRepo.query('CREATE EXTENSION IF NOT EXISTS vector');
473
- } catch (err: any) {
474
- logger.error(`Failed to initialize vector store - ${err}`);
475
- failure = true;
557
+ if (dbType === 'postgres') {
558
+ if (notInited) {
559
+ let failure = false;
560
+ try {
561
+ await vecRepo.query('CREATE EXTENSION IF NOT EXISTS vector');
562
+ } catch (err: any) {
563
+ logger.error(`Failed to initialize vector store - ${err}`);
564
+ failure = true;
565
+ }
566
+ if (failure) continue;
567
+ notInited = false;
476
568
  }
477
- if (failure) return;
478
- notInited = false;
569
+ await vecRepo.query(
570
+ `CREATE TABLE IF NOT EXISTS ${vecTableName} (
571
+ id varchar PRIMARY KEY,
572
+ embedding vector(${DefaultVectorDimension}),
573
+ ${TenantAttributeName} varchar,
574
+ __is_deleted__ boolean default false
575
+ )`
576
+ );
577
+ } else {
578
+ // sqlite-vec - vec0 doesn't support type declarations for metadata columns
579
+ await vecRepo.query(
580
+ `CREATE VIRTUAL TABLE IF NOT EXISTS ${vecTableName} USING vec0(
581
+ id TEXT PRIMARY KEY,
582
+ embedding FLOAT[${DefaultVectorDimension}])`
583
+ );
479
584
  }
480
- await vecRepo.query(
481
- `CREATE TABLE IF NOT EXISTS ${vecTableName} (
482
- id varchar PRIMARY KEY,
483
- embedding vector(${DefaultVectorDimension}),
484
- ${TenantAttributeName} varchar,
485
- __is_deleted__ boolean default false
486
- )`
487
- );
488
- });
585
+ }
489
586
  }
490
587
 
491
588
  export async function vectorStoreSearch(
@@ -494,7 +591,7 @@ export async function vectorStoreSearch(
494
591
  limit: number,
495
592
  ctx: DbContext
496
593
  ): Promise<any> {
497
- if (!isVectorStoreSupported()) {
594
+ if (!(await isVectorStoreSupported())) {
498
595
  // Not supported on sqljs/sqlite
499
596
  return [];
500
597
  }
@@ -508,18 +605,31 @@ export async function vectorStoreSearch(
508
605
  }
509
606
  const vecTableName = tableName + VectorSuffix;
510
607
  const qb = getDatasourceForTransaction(ctx.txnId).getRepository(tableName).manager;
511
- const { default: pgvector } = await import('pgvector');
512
- let ownersJoinCond: string = '';
608
+ const dbType = getDbType(AppConfig?.store);
513
609
  const tenantId = await ctx.getTenantId();
610
+ let ownersJoinCond: string = '';
514
611
  if (!hasGlobalPerms) {
515
612
  const ot = ownersTable(tableName);
516
613
  ownersJoinCond = `inner join ${ot} on
517
- ${ot}.path = ${vecTableName}.id and ${ot}.user_id = '${ctx.authInfo.userId}' and ${ot}.r = true
518
- and ${ot}.${TenantAttributeName} = '${tenantId}' and ${vecTableName}.${TenantAttributeName} = '${tenantId}'`;
614
+ ${ot}.path = ${vecTableName}.id and ${ot}.user_id = '${ctx.authInfo.userId}' and ${ot}.r = true
615
+ and ${ot}.${TenantAttributeName} = '${tenantId}'`;
616
+ }
617
+ if (dbType === 'postgres') {
618
+ const { default: pgvector } = await import('pgvector');
619
+ const sql = `select ${vecTableName}.id from ${vecTableName} ${ownersJoinCond} order by embedding <-> $1 LIMIT ${limit}`;
620
+ const args = pgvector.toSql(searchVec);
621
+ return await qb.query(sql, [args]);
622
+ } else {
623
+ // sqlite-vec - join with main table to filter by tenant
624
+ const alias = tableName.toLowerCase();
625
+ const sql = `SELECT ${vecTableName}.id FROM ${vecTableName}
626
+ INNER JOIN ${tableName} ${alias} ON ${alias}.${PathAttributeName} = ${vecTableName}.id
627
+ ${ownersJoinCond}
628
+ WHERE ${alias}.${TenantAttributeName} = '${tenantId}' AND ${alias}.${DeletedFlagAttributeName} = false AND ${vecTableName}.embedding MATCH $1
629
+ LIMIT ${limit}`;
630
+ const args = new Float32Array(searchVec);
631
+ return await qb.query(sql, [args]);
519
632
  }
520
- const sql = `select ${vecTableName}.id from ${vecTableName} ${ownersJoinCond} order by embedding <-> $1 LIMIT ${limit}`;
521
- const args = pgvector.toSql(searchVec);
522
- return await qb.query(sql, [args]);
523
633
  } catch (err: any) {
524
634
  logger.error(`Vector store search failed - ${err}`);
525
635
  return [];
@@ -531,16 +641,30 @@ export async function vectorStoreSearchEntryExists(
531
641
  id: string,
532
642
  ctx: DbContext
533
643
  ): Promise<boolean> {
534
- if (!isVectorStoreSupported()) return false;
644
+ if (!(await isVectorStoreSupported())) return false;
535
645
  try {
536
646
  const qb = getDatasourceForTransaction(ctx.txnId).getRepository(tableName).manager;
537
647
  const vecTableName = tableName + VectorSuffix;
648
+ const dbType = getDbType(AppConfig?.store);
538
649
  const tenantId = await ctx.getTenantId();
539
- const result: any[] = await qb.query(
540
- `select id from ${vecTableName} where id = $1 and ${TenantAttributeName} = '${tenantId}'`,
541
- [id]
542
- );
543
- return result !== null && result.length > 0;
650
+
651
+ if (dbType === 'postgres') {
652
+ const result: any[] = await qb.query(
653
+ `select id from ${vecTableName} where id = $1 and ${TenantAttributeName} = '${tenantId}'`,
654
+ [id]
655
+ );
656
+ return result !== null && result.length > 0;
657
+ } else {
658
+ // sqlite-vec - join with main table to verify tenant
659
+ const alias = tableName.toLowerCase();
660
+ const result: any[] = await qb.query(
661
+ `SELECT ${vecTableName}.id FROM ${vecTableName}
662
+ INNER JOIN ${tableName} ${alias} ON ${alias}.${PathAttributeName} = ${vecTableName}.id
663
+ WHERE ${vecTableName}.id = $1 AND ${alias}.${TenantAttributeName} = '${tenantId}'`,
664
+ [id]
665
+ );
666
+ return result !== null && result.length > 0;
667
+ }
544
668
  } catch (err: any) {
545
669
  logger.error(`Vector store search failed - ${err}`);
546
670
  }
@@ -548,15 +672,22 @@ export async function vectorStoreSearchEntryExists(
548
672
  }
549
673
 
550
674
  export async function deleteFullTextSearchEntry(tableName: string, id: string, ctx: DbContext) {
551
- if (!isVectorStoreSupported()) return;
675
+ if (!(await isVectorStoreSupported())) return;
552
676
  try {
553
677
  const qb = getDatasourceForTransaction(ctx.txnId).getRepository(tableName).manager;
554
678
  const vecTableName = tableName + VectorSuffix;
679
+ const dbType = getDbType(AppConfig?.store);
555
680
  const tenantId = await ctx.getTenantId();
556
- await qb.query(
557
- `delete from ${vecTableName} where id = $1 and ${TenantAttributeName} = '${tenantId}'`,
558
- [id]
559
- );
681
+
682
+ if (dbType === 'postgres') {
683
+ await qb.query(
684
+ `delete from ${vecTableName} where id = $1 and ${TenantAttributeName} = '${tenantId}'`,
685
+ [id]
686
+ );
687
+ } else {
688
+ // sqlite-vec - delete just by id (ownership verified by caller)
689
+ await qb.query(`delete from ${vecTableName} where id = $1`, [id]);
690
+ }
560
691
  } catch (err: any) {
561
692
  logger.error(`Vector store delete failed - ${err}`);
562
693
  }