@melandlabs/memory-store 0.1.5 → 0.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/dist/{config-D6MzksfT.d.ts → config-BYfTzG3h.d.ts} +17 -0
- package/dist/contracts.d.ts +7 -0
- package/dist/contracts.js +0 -2
- package/dist/http.d.ts +1 -1
- package/dist/http.js +144 -23
- package/dist/index.d.ts +2 -2
- package/dist/index.js +144 -23
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +144 -23
- package/dist/policies/memory-graph-correction-policy.js +0 -2
- package/dist/policies/memory-graph-write-policy.js +0 -2
- package/dist/search/unified-search.d.ts +39 -3
- package/dist/search/unified-search.js +145 -24
- package/dist/server/cli-http.js +144 -23
- package/dist/server/cli-mcp.js +144 -23
- package/dist/server/cli-shared.d.ts +1 -1
- package/dist/server/cli-shared.js +0 -2
- package/dist/storage/chroma-memory-index.js +0 -2
- package/dist/storage/postgres-raw-message-factory.d.ts +1 -1
- package/dist/storage/postgres-raw-message-factory.js +0 -2
- package/dist/storage/raw-message-store.d.ts +9 -1
- package/dist/storage/raw-message-store.js +0 -2
- package/dist/storage/sqlite-raw-message-store.d.ts +15 -2
- package/dist/storage/sqlite-raw-message-store.js +8 -3
- package/dist/storage/sqlite-vector-index.d.ts +1 -1
- package/dist/storage/sqlite-vector-index.js +0 -2
- package/package.json +8 -8
- package/dist/contracts.js.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/policies/memory-graph-correction-policy.js.map +0 -1
- package/dist/policies/memory-graph-write-policy.js.map +0 -1
- package/dist/search/unified-search.js.map +0 -1
- package/dist/server/cli-http.js.map +0 -1
- package/dist/server/cli-mcp.js.map +0 -1
- package/dist/server/cli-shared.js.map +0 -1
- package/dist/storage/chroma-memory-index.js.map +0 -1
- package/dist/storage/postgres-raw-message-factory.js.map +0 -1
- package/dist/storage/raw-message-store.js.map +0 -1
- package/dist/storage/sqlite-raw-message-store.js.map +0 -1
- package/dist/storage/sqlite-vector-index.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/postgres-raw-message-factory.ts","../../src/storage/chroma-memory-index.ts","../../src/storage/sqlite-raw-message-store.ts","../../src/storage/raw-message-store.ts","../../src/storage/sqlite-vector-index.ts","../../src/server/cli-shared.ts"],"names":["manager"],"mappings":";;;;;;;;;AA4CA,IAAI,OAAA,GAAoC,IAAA;AAUxC,eAAsB,uBACrB,GAAA,EACgD;AAChD,EAAc,OAAO,IAAA;AAEtB;AAEO,SAAS,kBAAA,GAA8B;AAC7C,EAAA,OAAO,OAAA,KAAY,IAAA;AACpB;AC9CA,IAAM,2BAAA,GAA8B;AAAA,EACnC,kCAAA;AAAA,EACA,6BAAA;AAAA,EACA;AACD,CAAA;AA+CA,SAAS,WAAW,IAAA,EAAiC;AACpD,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACvB,IAAA,MAAM,QAAQ,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG,IAAA,GAAO,WAAA,EAAY;AACnD,IAAA,IAAI,KAAA,EAAO;AACV,MAAA,OAAO,KAAA;AAAA,IACR;AAAA,EACD;AACA,EAAA,OAAO,EAAA;AACR;AAEO,SAAS,yBAAA,GAAqC;AACpD,EAAA,OAAO,UAAA,CAAW,2BAA2B,CAAA,KAAM,QAAA;AACpD;;;AC5DA,IAAI,OAAA,GAA0C,IAAA;AAE9C,IAAM,sBAAsB,IAAA,CAAK,OAAA,EAAQ,EAAG,cAAA,EAAgB,UAAU,UAAU,CAAA;AAMzE,SAAS,6BAAA,GAAwC;AACvD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,oBAAA,EAAsB,IAAA,EAAK;AACvD,EAAA,OAAO,OAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,GAAI,OAAA,GAAU,mBAAA;AAClD;AAUA,eAAsB,2BAA2B,IAAA,EAAyD;AACzG,EAAA,IAAI,CAAC,OAAA,EAAS;AACb,IAAA,MAAM,SAAS,6BAAA,EAA8B;AAC7C,IAAA,SAAA,CAAU,QAAQ,MAAM,CAAA,EAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC9C,IAAA,OAAA,GAAU,IAAI,uBAAA,CAAwB;AAAA,MACrC,MAAA;AAAA,MACA,kBAAA,EAAoB,CAAC,yBAAA;AAA0B,KAC/C,CAAA;AACD,IAAA,MAAM,QAAQ,IAAA,EAAK;AAAA,EACpB;AAEA,EAAA,OAAO,OAAA;AACR;AAEA,eAAsB,4BAAA,GAA8C;AACnE,EAAA,IAAI,CAAC,OAAA,EAAS;AACb,IAAA;AAAA,EACD;AACA,EAAA,MAAM,QAAQ,KAAA,EAAM;AACpB,EAAA,OAAA,GAAU,IAAA;AACX;;;ACTA,SAAS,eAAe,GAAA,EAA2D;AAClF,EAAA,MAAM,WAAW,OAAA,CAAQ,GAAA,CAAI,gCAAA,EAAkC,IAAA,GAAO,WAAA,EAAY;AAClF,EAAA,IAAI,QAAA,KAAa,YAAY,OAAO,UAAA;AAGpC,EAAA,OAAO,QAAA;AACR;AAEA,SAAS,WAAW,IAAA,EAAuC;AAC1D,EAAA,OAAO,EAAC;AACT;AAEO,SAAS,qBAAA,CAAsB,OAAA,GAAwC,EAAC,EAAoB;AAClG,EAAY,UAAA,CAAW,OAAA,CAAQ,GAAG;AAElC,EAAA,OAAO;AAAA,IACN,UAAA,GAAuC;AACtC,MAAA,OAAO,eAAkB,CAAA;AAAA,IAC1B,CAAA;AAAA,IACA,WAAA,GAAuB;AAGtB,MAAA,OAAO,cAAA,CAAkB,CAAA,KAAM,QAAA,IAAY,kBAAA,EAAmB;AAAA,IAC/D,CAAA;AAAA,IACA,MAAM,UAAA,GAA0D;AAC/D,MAAA,IAAI,cAAA,CAAkB,CAAA,KAAM,UAAA,EAAY;AACvC,QAAA,MAAM,EAAA,GAAK,MAAM,sBAAA,CAA0B,CAAA;AAC3C,QAAA,IAAI,CAAC,EAAA,EAAI;AACR,UAAA,MAAM,IAAI,KAAA;AAAA,YACT;AAAA,WAED;AAAA,QACD;AACA,QAAA,OAAO,EAAA;AAAA,MACR;AACA,MAAA,OAAQ,MAAM,2BAA8B,CAAA;AAAA,IAC7C,CAAA;AAAA,IACA,MAAM,KAAA,GAAuB;AAG5B,MAAA,MAAM,4BAAA,EAA6B;AAAA,IACpC;AAAA,GACD;AACD;;;ACtDA,SAAS,2BAAA,GAAuD;AAC/D,EAAA,MAAM,OAAA,GAAA,CACL,OAAA,CAAQ,GAAA,CAAI,4BAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,2BAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,oBAAA,IACZ,YAAA,EACC,WAAA,EAAY;AACd,EAAA,OAAO,OAAA,KAAY,WAAW,QAAA,GAAW,YAAA;AAC1C;AAEO,SAAS,0BAA0B,IAAA,EAAgC;AACzE,EAAA,OAAO,6BAA4B,KAAM,YAAA;AAC1C;AAMA,eAAe,yBAAyB,IAAA,EAAsB;AAC7D,EAAA,MAAM,SAAS,6BAAA,EAA8B;AAC7C,EAAA,MAAM,EAAE,iBAAA,EAAkB,GAAI,MAAM,OAAO,kCAAkC,CAAA;AAC7E,EAAA,OAAO,MAAM,iBAAA,CAAkB,MAAA,EAAQ,MAAA,EAAW;AAAA,IACjD,cAAA,EAAgB,OAAA,CAAQ,GAAA,CAAI,8BAAA,IAAkC;AAAA,GAC9D,CAAA;AACF;AAsCA,eAAsB,2BAAA,CACrB,OACA,GAAA,EACgC;AAChC,EAAA,MAAM,KAAA,GAAQ,MAAM,wBAAA,CAAwC,CAAA;AAC5D,EAAA,MAAM,iBAAiB,IAAA,CAAK,GAAA,CAAI,MAAM,KAAA,GAAQ,CAAA,EAAG,MAAM,KAAK,CAAA;AAC5D,EAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,2BAAA,CAA4B,MAAM,cAAA,EAAgB;AAAA,IAC7E,KAAA,EAAO,cAAA;AAAA,IACP,MAAA,EAAQ,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA;AAAO,GAC/B,CAAA;AAED,EAAA,OAAO,OAAA,CACL,MAAA,CAAO,CAAC,MAAA,KAAW,MAAA,CAAO,KAAA,IAAS,KAAA,CAAM,SAAS,CAAA,CAClD,MAAA,CAAO,CAAC,MAAA,KAAW;AACnB,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,IAAY,EAAC;AACrC,IAAA,IAAI,KAAA,CAAM,MAAA,EAAQ,MAAA,IAAU,CAAC,KAAA,CAAM,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,QAAA,CAAS,KAAA,IAAS,EAAE,CAAC,CAAA,EAAG;AACjF,MAAA,OAAO,KAAA;AAAA,IACR;AACA,IAAA,OAAO,KAAA,CAAM,eAAA,IAAmB,QAAA,CAAS,QAAA,KAAa,IAAA;AAAA,EACvD,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,EAAG,MAAM,KAAK,CAAA;AACvB;;;ACxEA,eAAe,SAAA,GAAmC;AACjD,EAAA,IAAI;AACH,IAAA,MAAM,CAAC,KAAA,EAAO,MAAM,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MACzC,OAAO,0DAA0D,CAAA;AAAA,MACjE,OAAO,iCAAiC;AAAA,KACxC,CAAA;AACD,IAAA,OAAO;AAAA,MACN,oCACC,KAAA,CAAM,kCAAA;AAAA,MACP,mBAAmB,MAAA,CAAO;AAAA,KAC3B;AAAA,EACD,SAAS,KAAA,EAAO;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,gJAAA,EAAoJ,MAAgB,OAAO,CAAA,CAAA;AAAA,KAC5K;AAAA,EACD;AACD;AAEO,SAAS,iBAAiB,IAAA,EAA6B;AAC7D,EAAA,MAAM,MAAM,OAAA,CAAQ,GAAA;AACpB,EAAA,MAAM,IAAA,GAAoB;AAAA,IACzB,iBAAA,EAAoB,IAAI,kBAAA,IAAuE,MAAA;AAAA,IAC/F,gBAAgB,GAAA,CAAI,eAAA;AAAA,IACpB,WAAW,GAAA,CAAI,UAAA;AAAA,IACf,aAAA,EAAgB,IAAI,cAAA,IAA+D,MAAA;AAAA,IACnF,eAAA,EAAkB,IAAI,gBAAA,IAAmE,MAAA;AAAA,IACzF,kBAAA,EAAoB,IAAI,mBAAA,IAAuB,sBAAA;AAAA,IAC/C,gBAAA,EAAmB,IAAI,iBAAA,IAAqE,MAAA;AAAA,IAC5F,mBAAA,EAAqB,IAAI,oBAAA,IAAwB;AAAA,GAClD;AACA,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,KAAK,CAAA,EAAG;AACxC,IAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAClB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA;AACvB,IAAA,MAAM,YAAY,MAAM;AACvB,MAAA,IAAI,SAAS,MAAA,EAAW,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,GAAG,CAAA,iBAAA,CAAmB,CAAA;AACrF,MAAA,CAAA,IAAK,CAAA;AACL,MAAA,OAAO,IAAA;AAAA,IACR,CAAA;AACA,IAAA,QAAQ,GAAA;AAAK,MACZ,KAAK,sBAAA;AACJ,QAAA,IAAA,CAAK,oBAAoB,SAAA,EAAU;AACnC,QAAA;AAAA,MACD,KAAK,mBAAA;AACJ,QAAA,IAAA,CAAK,iBAAiB,SAAA,EAAU;AAChC,QAAA;AAAA,MACD,KAAK,cAAA;AACJ,QAAA,IAAA,CAAK,YAAY,SAAA,EAAU;AAC3B,QAAA;AAAA,MACD,KAAK,kBAAA;AACJ,QAAA,IAAA,CAAK,gBAAgB,SAAA,EAAU;AAC/B,QAAA;AAAA,MACD,KAAK,oBAAA;AACJ,QAAA,IAAA,CAAK,kBAAkB,SAAA,EAAU;AACjC,QAAA;AAAA,MACD,KAAK,uBAAA;AACJ,QAAA,IAAA,CAAK,qBAAqB,SAAA,EAAU;AACpC,QAAA;AAAA,MACD,KAAK,qBAAA;AACJ,QAAA,IAAA,CAAK,mBAAmB,SAAA,EAAU;AAClC,QAAA;AAAA,MACD,KAAK,wBAAA;AACJ,QAAA,IAAA,CAAK,sBAAsB,SAAA,EAAU;AACrC,QAAA;AAAA;AACF,EACD;AACA,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,CAAA,IAAK;AAAA,IAC3B,CAAC,sBAAA,EAAwB,IAAA,CAAK,iBAAiB,CAAA;AAAA,IAC/C,CAAC,kBAAA,EAAoB,IAAA,CAAK,aAAa,CAAA;AAAA,IACvC,CAAC,oBAAA,EAAsB,IAAA,CAAK,eAAe,CAAA;AAAA,IAC3C,CAAC,qBAAA,EAAuB,IAAA,CAAK,gBAAgB;AAAA,GAC9C,EAAY;AACX,IAAA,MAAM,UAAU,CAAC,OAAA,EAAS,YAAA,EAAc,MAAA,EAAQ,UAAU,YAAY,CAAA;AACtE,IAAA,IAAI,CAAE,OAAA,CAA8B,QAAA,CAAS,KAAK,CAAA,EAAG;AACpD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,IAAI,CAAA,iBAAA,EAAoB,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,OAAA,EAAU,KAAK,CAAA,EAAA,CAAI,CAAA;AAAA,IACpG;AAAA,EACD;AACA,EAAA,OAAO,IAAA;AACR;AAEA,eAAsB,aAAa,IAAA,EAA+C;AACjF,EAAA,MAAM,UAA6B,EAAC;AACpC,EAAA,MAAM,MAAM,CAAC,GAAA,KAAgB,QAAQ,IAAA,CAAK,CAAA,mBAAA,EAAsB,GAAG,CAAA,CAAE,CAAA;AAErE,EAAA,MAAM,UAAA,GACL,IAAA,CAAK,iBAAA,KAAsB,OAAA,IAC3B,IAAA,CAAK,aAAA,KAAkB,QAAA,IACvB,IAAA,CAAK,eAAA,KAAoB,QAAA,IACzB,IAAA,CAAK,gBAAA,KAAqB,QAAA;AAC3B,EAAA,MAAM,KAAA,GAAQ,UAAA,GAAa,MAAM,SAAA,EAAU,GAAI,IAAA;AAI/C,EAAA,IAAI,IAAA,CAAK,sBAAsB,OAAA,EAAS;AACvC,IAAA,MAAM,QAAA,GAAW,IAAI,KAAA,CAAO,kCAAA,CAAmC,EAAE,SAAA,EAAW,IAAA,CAAK,gBAAgB,CAAA;AACjG,IAAA,OAAA,CAAQ,aAAa,OAAO,EAAE,OAAM,KAAM,QAAA,CAAS,WAAW,KAAK,CAAA;AACnE,IAAA,GAAA;AAAA,MACC,CAAA,+DAAA,EAAkE,IAAA,CAAK,cAAA,IAAkB,yBAAyB,CAAA,CAAA;AAAA,KACnH;AAAA,EACD,CAAA,MAAA,IAAW,IAAA,CAAK,iBAAA,KAAsB,YAAA,EAAc;AACnD,IAAA,MAAM,MAAA,GAAS,QAAQ,GAAA,CAAI,kBAAA;AAC3B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACZ,MAAA,MAAM,IAAI,MAAM,gFAAgF,CAAA;AAAA,IACjG;AACA,IAAA,MAAM,KAAA,GAAQ,KAAK,cAAA,IAAkB,wBAAA;AACrC,IAAA,MAAM,OAAA,GAAU,8BAAA;AAChB,IAAA,OAAA,CAAQ,UAAA,GAAa,OAAO,EAAE,KAAA,EAAM,KAAM;AACzC,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,WAAA,CAAA,EAAe;AAAA,QAChD,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACR,cAAA,EAAgB,kBAAA;AAAA,UAChB,aAAA,EAAe,UAAU,MAAM,CAAA,CAAA;AAAA,UAC/B,cAAA,EAAgB,OAAA,CAAQ,GAAA,CAAI,mBAAA,IAAuB,wBAAA;AAAA,UACnD,SAAA,EAAW;AAAA,SACZ;AAAA,QACA,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO;AAAA,OAC5C,CAAA;AACD,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACZ,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,GAAA,CAAI,MAAM,KAAK,MAAM,GAAA,CAAI,IAAA,EAAM,CAAA,CAAE,CAAA;AAAA,MAC3E;AACA,MAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,GAAO,CAAC,CAAA,EAAG,SAAA;AAClC,MAAA,IAAI,CAAC,SAAA,EAAW,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAC1F,MAAA,OAAO,SAAA;AAAA,IACR,CAAA;AACA,IAAA,GAAA,CAAI,CAAA,uCAAA,EAA0C,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,EACvD;AAGA,EAAA,IAAI,IAAA,CAAK,kBAAkB,YAAA,EAAc;AACxC,IAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,EAAE,GAAA,EAAK,QAAW,CAAA;AACtD,IAAA,MAAMA,QAAAA,GAAU,MAAM,KAAA,CAAM,UAAA,EAAW;AACvC,IAAA,IAAI,OAAOA,QAAAA,CAAQ,0BAAA,KAA+B,UAAA,EAAY;AAC7D,MAAA,MAAM,IAAI,KAAA;AAAA,QACT;AAAA,OAED;AAAA,IACD;AACA,IAAA,OAAA,CAAQ,oBAAA,GAAuB,OAAO,EAAE,MAAA,EAAQ,gBAAgB,KAAA,EAAO,SAAA,EAAW,OAAM,KAAM;AAC7F,MAAA,MAAM,IAAA,GAAQ,MAAMA,QAAAA,CAAQ,0BAAA,CAA4B;AAAA,QACvD,MAAA;AAAA,QACA,cAAA;AAAA,QACA,KAAA;AAAA,QACA,SAAA;AAAA,QACA;AAAA,OACA,CAAA;AACD,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACvB,IAAI,CAAA,CAAE,EAAA;AAAA,QACN,SAAS,CAAA,CAAE,OAAA;AAAA,QACX,YAAY,CAAA,CAAE,UAAA;AAAA,QACd,QAAA,EAAU,CAAA,CAAE,QAAA,IAAY;AAAC,OAC1B,CAAE,CAAA;AAAA,IACH,CAAA;AACA,IAAA,GAAA,CAAI,qFAAqF,CAAA;AAAA,EAC1F,CAAA,MAAA,IAAW,IAAA,CAAK,aAAA,KAAkB,QAAA,EAAU;AAC3C,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA;AACT,MAAA,MAAM,IAAI,MAAM,yEAAyE,CAAA;AAC1F,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAO,iBAAA,CAAkB;AAAA,MAC1C,KAAK,IAAA,CAAK,SAAA;AAAA,MACV,cAAA,EAAgB;AAAA,KAChB,CAAA;AACD,IAAA,OAAA,CAAQ,uBAAuB,OAAO,EAAE,cAAA,EAAgB,KAAA,EAAO,WAAU,KAAM;AAC9E,MAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,2BAAA,CAA4B,gBAAgB,EAAE,KAAA,EAAO,KAAA,GAAQ,CAAA,EAAG,CAAA;AAC5F,MAAA,OAAO,OAAA,CACL,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,IAAS,SAAS,CAAA,CAClC,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,EAAA,EAAI,EAAE,EAAA,EAAI,OAAA,EAAS,CAAA,CAAE,OAAA,EAAS,UAAA,EAAY,CAAA,CAAE,KAAA,EAAO,QAAA,EAAU,CAAA,CAAE,QAAA,IAAY,EAAC,EAAE,CAAE,CAAA;AAAA,IACjG,CAAA;AACA,IAAA,GAAA,CAAI,uEAAuE,CAAA;AAAA,EAC5E;AAGA,EAAA,IAAI,IAAA,CAAK,eAAA,KAAoB,YAAA,IAAgB,yBAAA,EAA0B,EAAG;AACzE,IAAA,IAAI,CAAC,QAAQ,UAAA,EAAY;AACxB,MAAA,MAAM,IAAI,MAAM,8EAA8E,CAAA;AAAA,IAC/F;AACA,IAAA,MAAM,aAAa,OAAA,CAAQ,UAAA;AAC3B,IAAA,OAAA,CAAQ,cAAA,GAAiB,OAAO,EAAE,MAAA,EAAQ,OAAO,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,eAAA,EAAgB,KAAM;AAChG,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,EAAE,MAAA,EAAQ,OAAO,CAAA;AAC9C,MAAA,MAAM,IAAA,GAAO,MAAM,2BAAA,CAA4B;AAAA,QAC9C,MAAA;AAAA,QACA,cAAA,EAAgB,GAAA;AAAA,QAChB,KAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACA,CAAA;AACD,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACvB,IAAI,CAAA,CAAE,EAAA;AAAA,QACN,SAAS,CAAA,CAAE,OAAA;AAAA,QACX,YAAY,CAAA,CAAE,KAAA;AAAA,QACd,QAAA,EAAU,CAAA,CAAE,QAAA,IAAY;AAAC,OAC1B,CAAE,CAAA;AAAA,IACH,CAAA;AACA,IAAA,GAAA,CAAI,uCAAuC,CAAA;AAAA,EAC5C,CAAA,MAAA,IAAW,IAAA,CAAK,eAAA,KAAoB,QAAA,EAAU;AAC7C,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA;AACT,MAAA,MAAM,IAAI,MAAM,2EAA2E,CAAA;AAC5F,IAAA,IAAI,CAAC,OAAA,CAAQ,UAAA;AACZ,MAAA,MAAM,IAAI,MAAM,0EAA0E,CAAA;AAC3F,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAO,iBAAA,CAAkB;AAAA,MAC1C,KAAK,IAAA,CAAK,SAAA;AAAA,MACV,gBAAgB,IAAA,CAAK;AAAA,KACrB,CAAA;AACD,IAAA,MAAM,aAAa,OAAA,CAAQ,UAAA;AAC3B,IAAA,OAAA,CAAQ,iBAAiB,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,WAAU,KAAM;AAC/D,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,EAAE,MAAA,EAAQ,EAAA,EAAI,OAAO,CAAA;AAClD,MAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,2BAAA,CAA4B,KAAK,EAAE,KAAA,EAAO,KAAA,GAAQ,CAAA,EAAG,CAAA;AACjF,MAAA,OAAO,OAAA,CACL,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,IAAS,SAAS,CAAA,CAClC,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,EAAA,EAAI,EAAE,EAAA,EAAI,OAAA,EAAS,CAAA,CAAE,OAAA,EAAS,UAAA,EAAY,CAAA,CAAE,KAAA,EAAO,QAAA,EAAU,CAAA,CAAE,QAAA,IAAY,EAAC,EAAE,CAAE,CAAA;AAAA,IACjG,CAAA;AACA,IAAA,GAAA,CAAI,CAAA,8CAAA,EAAiD,IAAA,CAAK,kBAAkB,CAAA,CAAA,CAAG,CAAA;AAAA,EAChF;AAGA,EAAA,IAAI,IAAA,CAAK,qBAAqB,QAAA,EAAU;AACvC,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA;AACT,MAAA,MAAM,IAAI,MAAM,4EAA4E,CAAA;AAC7F,IAAA,IAAI,CAAC,OAAA,CAAQ,UAAA;AACZ,MAAA,MAAM,IAAI,MAAM,2EAA2E,CAAA;AAC5F,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAO,iBAAA,CAAkB;AAAA,MAC1C,KAAK,IAAA,CAAK,SAAA;AAAA,MACV,gBAAgB,IAAA,CAAK;AAAA,KACrB,CAAA;AACD,IAAA,MAAM,aAAa,OAAA,CAAQ,UAAA;AAC3B,IAAA,OAAA,CAAQ,eAAA,GAAkB,OAAO,EAAE,KAAA,EAAO,SAAQ,KAAM;AACvD,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,EAAE,MAAA,EAAQ,EAAA,EAAI,OAAO,CAAA;AAClD,MAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,2BAAA,CAA4B,GAAA,EAAK,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,GAAQ,CAAA,EAAG,CAAA;AACzF,MAAA,OAAO,OAAA,CACL,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,KAAA,IAAS,OAAA,CAAQ,SAAS,CAAA,CAC1C,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,MAAO;AAAA,QACf,SAAS,CAAA,CAAE,EAAA;AAAA,QACX,UAAA,EAAY,EAAE,UAAA,IAAc,MAAA,CAAO,EAAE,QAAA,EAAU,UAAA,IAAc,EAAE,EAAE,CAAA;AAAA,QACjE,YAAA,EAAc,MAAA,CAAO,CAAA,CAAE,QAAA,EAAU,gBAAgB,EAAE,CAAA;AAAA,QACnD,SAAS,CAAA,CAAE,OAAA;AAAA,QACX,YAAY,CAAA,CAAE,KAAA;AAAA,QACd,UAAA,EAAY;AAAA,OACb,CAAE,CAAA;AAAA,IACJ,CAAA;AACA,IAAA,GAAA,CAAI,CAAA,+CAAA,EAAkD,IAAA,CAAK,mBAAmB,CAAA,CAAA,CAAG,CAAA;AAAA,EAClF;AAEA,EAAA,OAAO,OAAA;AACR;AAOO,SAAS,gBAAA,GAAyB;AACxC,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kEAAA,CAmBsD,CAAA;AACnE","file":"cli-shared.js","sourcesContent":["/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n","/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n","/**\n * Top-level raw-message store facade.\n *\n * Backend selection is env-var driven:\n *\n * - `OPENCONTEXT_MEMORY_STORE_BACKEND=postgres` → use the host's\n * registered Postgres factory. A factory MUST be registered first\n * via `registerPostgresFactory()`; otherwise this throws a clear\n * error rather than silently falling back.\n * - Any other value (including unset) → local SQLite. The default\n * works in every host environment with no extra configuration.\n *\n * The facade exposes the common `RawMessageStorageManager` contract plus\n * a typed `searchMessagesSemantically` extension when present.\n */\n\nimport type { RawMessageStorageManager } from \"@melandlabs/indexeddb/storage\";\nimport type { MemoryStoreConfig, MemoryStoreEnv } from \"../config\";\nimport { hasPostgresFactory, resolvePostgresFactory } from \"./postgres-raw-message-factory\";\nimport { closeSQLiteRawMessageManager, getSQLiteRawMessageManager } from \"./sqlite-raw-message-store\";\n\nexport type RawMessageStorageBackend = \"sqlite\" | \"postgres\";\n\nexport type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {\n\tsearchMessagesSemantically?: (input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}) => Promise<unknown[]>;\n};\n\nexport interface CreateRawMessageStoreOptions {\n\tenv?: MemoryStoreEnv;\n}\n\nexport interface RawMessageStore {\n\tgetManager(): Promise<RawMessageStorageManagerWithSearch>;\n\tgetBackend(): RawMessageStorageBackend;\n\tisAvailable(): boolean;\n\tclose(): Promise<void>;\n}\n\nfunction resolveBackend(env: MemoryStoreEnv | undefined): RawMessageStorageBackend {\n\tconst explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();\n\tif (explicit === \"postgres\") return \"postgres\";\n\t// Any other value — including the default \"sqlite\", an unknown value,\n\t// or the env var being unset — falls through to local SQLite.\n\treturn \"sqlite\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nexport function createRawMessageStore(options: CreateRawMessageStoreOptions = {}): RawMessageStore {\n\tconst env = resolveEnv(options.env);\n\n\treturn {\n\t\tgetBackend(): RawMessageStorageBackend {\n\t\t\treturn resolveBackend(env);\n\t\t},\n\t\tisAvailable(): boolean {\n\t\t\t// SQLite is always available; postgres is only available when the\n\t\t\t// env var asks for it AND a factory has been registered.\n\t\t\treturn resolveBackend(env) === \"sqlite\" || hasPostgresFactory();\n\t\t},\n\t\tasync getManager(): Promise<RawMessageStorageManagerWithSearch> {\n\t\t\tif (resolveBackend(env) === \"postgres\") {\n\t\t\t\tconst pg = await resolvePostgresFactory(env);\n\t\t\t\tif (!pg) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. \" +\n\t\t\t\t\t\t\t\"Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn pg as unknown as RawMessageStorageManagerWithSearch;\n\t\t\t}\n\t\t\treturn (await getSQLiteRawMessageManager(env)) as unknown as RawMessageStorageManagerWithSearch;\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\t// The sqlite singleton is process-wide, so close regardless of the\n\t\t\t// env var's current value — the previous call may have used it.\n\t\t\tawait closeSQLiteRawMessageManager();\n\t\t},\n\t};\n}\n\n// Module-level singleton so existing call sites that imported the\n// legacy `getRawMessageManager()` keep working without a refactor.\nlet moduleStore: RawMessageStore | null = null;\nlet moduleConfig: MemoryStoreConfig | null = null;\n\nexport function configureRawMessageStore(config: MemoryStoreConfig): RawMessageStore {\n\tmoduleConfig = config;\n\tmoduleStore = createRawMessageStore({ env: config.env });\n\treturn moduleStore;\n}\n\nexport function getRawMessageStorageBackend(): RawMessageStorageBackend {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getBackend();\n}\n\nexport function isRawMessageStorageAvailable(): boolean {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.isAvailable();\n}\n\nexport async function getRawMessageManager(): Promise<RawMessageStorageManagerWithSearch> {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getManager();\n}\n\nexport async function closeRawMessageStore(): Promise<void> {\n\tif (!moduleStore) return;\n\tawait moduleStore.close();\n\tmoduleStore = null;\n}\n","/**\n * SQLite-vec-backed raw-message + insight vector index.\n *\n * Mirrors the chroma-memory-index interface but uses the local\n * sqlite-vec store. The DB path is resolved from the same env-var chain\n * the raw-message SQLite layer uses.\n */\n\nimport type { VectorSearchResult } from \"@melandlabs/rag/vector-service\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { resolveSQLiteRawMessageDbPath } from \"./sqlite-raw-message-store\";\n\nexport interface SQLiteInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface SQLiteInsightSearchInput {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}\n\nfunction getMemoryVectorStoreBackend(): \"chroma\" | \"sqlite-vec\" {\n\tconst backend = (\n\t\tprocess.env.INSIGHT_VECTOR_STORE_BACKEND ||\n\t\tprocess.env.MEMORY_VECTOR_STORE_BACKEND ||\n\t\tprocess.env.VECTOR_STORE_BACKEND ||\n\t\t\"sqlite-vec\"\n\t).toLowerCase();\n\treturn backend === \"chroma\" ? \"chroma\" : \"sqlite-vec\";\n}\n\nexport function isInsightSQLiteVecEnabled(_env?: MemoryStoreEnv): boolean {\n\treturn getMemoryVectorStoreBackend() === \"sqlite-vec\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nasync function getInsightSQLiteVecStore(_env: MemoryStoreEnv) {\n\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\tconst { getSQLiteVecStore } = await import(\"@melandlabs/rag/sqlite-vec-store\");\n\treturn await getSQLiteVecStore(dbPath, undefined, {\n\t\tcollectionName: process.env.SQLITE_VEC_INSIGHTS_COLLECTION || \"opencontext_insights\",\n\t});\n}\n\nexport async function upsertInsightsToSQLiteVec(\n\tinsights: SQLiteInsightVectorInput[],\n\tenv?: MemoryStoreEnv,\n): Promise<number> {\n\tif (!isInsightSQLiteVecEnabled(env) || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = await getInsightSQLiteVecStore(resolveEnv(env));\n\tawait store.addChunks(\n\t\tinsights.map((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: normalizeTime(item.time),\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t})),\n\t);\n\treturn insights.length;\n}\n\nexport async function searchInsightsWithSQLiteVec(\n\tinput: SQLiteInsightSearchInput,\n\tenv?: MemoryStoreEnv,\n): Promise<VectorSearchResult[]> {\n\tconst store = await getInsightSQLiteVecStore(resolveEnv(env));\n\tconst overfetchLimit = Math.max(input.limit * 8, input.limit);\n\tconst results = await store.similaritySearchWithOptions(input.queryEmbedding, {\n\t\tlimit: overfetchLimit,\n\t\tfilter: { userId: input.userId },\n\t});\n\n\treturn results\n\t\t.filter((result) => result.score >= input.threshold)\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (input.botIds?.length && !input.botIds.includes(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn input.includeArchived || metadata.archived !== true;\n\t\t})\n\t\t.slice(0, input.limit);\n}\n\nfunction normalizeTime(value: unknown): number | null {\n\tif (value instanceof Date) return value.getTime();\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\") {\n\t\tconst parsed = Date.parse(value);\n\t\treturn Number.isFinite(parsed) ? parsed : null;\n\t}\n\treturn null;\n}\n\nfunction toStringValue(value: unknown): string {\n\treturn typeof value === \"string\" ? value : \"\";\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n","#!/usr/bin/env node\n/**\n * Shared argv parsing + `unified.*` wiring for the memory-store CLI bins.\n *\n * Both `cli-http.ts` (the HTTP daemon) and `cli-mcp.ts` (the MCP daemon)\n * take the same `--embedding-provider` / `--*-backend` flag surface —\n * the MCP server exposes the same `searchUnifiedMemory` tool the HTTP\n * `/v1/search` route does, so they must speak the same config. This\n * module owns that surface so the two bins stay in lock-step.\n *\n * `--embedding-provider local` and every `--*-backend=chroma` value\n * require `@melandlabs/ai-rag` (a peer install — pulling it in adds\n * `@huggingface/transformers`, `chromadb`, and ~30 MB of ONNX weights\n * on first run). The bin errors with a clear remediation message if the\n * package is missing.\n */\n\nimport type { UnifiedSearchDeps } from \"../config\";\nimport { createRawMessageStore } from \"../storage/raw-message-store\";\nimport { isInsightSQLiteVecEnabled, searchInsightsWithSQLiteVec } from \"../storage/sqlite-vector-index\";\n\nexport interface UnifiedArgs {\n\tembeddingProvider: \"local\" | \"openrouter\" | \"none\";\n\tembeddingModel?: string;\n\tchromaUrl?: string;\n\tmemoryBackend: \"sqlite-vec\" | \"chroma\" | \"none\";\n\tinsightsBackend: \"sqlite-vec\" | \"chroma\" | \"none\";\n\tinsightsCollection: string;\n\tknowledgeBackend: \"chroma\" | \"none\";\n\tknowledgeCollection: string;\n}\n\ninterface AiRagModules {\n\tLocalTransformersEmbeddingProvider: new (opts: { modelName?: string }) => {\n\t\tembedQuery(text: string): Promise<number[]>;\n\t};\n\tChromaVectorStore: new (opts: { url?: string; collectionName: string }) => {\n\t\tsimilaritySearchWithOptions(\n\t\t\tqueryEmbedding: number[],\n\t\t\toptions: { limit?: number },\n\t\t): Promise<\n\t\t\tArray<{\n\t\t\t\tid: string;\n\t\t\t\tcontent: string;\n\t\t\t\tscore: number;\n\t\t\t\tdocumentId: string;\n\t\t\t\tmetadata?: Record<string, unknown>;\n\t\t\t}>\n\t\t>;\n\t};\n}\n\nasync function loadAiRag(): Promise<AiRagModules> {\n\ttry {\n\t\tconst [local, chroma] = await Promise.all([\n\t\t\timport(\"@melandlabs/ai-rag/local-transformers-embedding-provider\"),\n\t\t\timport(\"@melandlabs/ai-rag/chroma-store\"),\n\t\t]);\n\t\treturn {\n\t\t\tLocalTransformersEmbeddingProvider:\n\t\t\t\tlocal.LocalTransformersEmbeddingProvider as AiRagModules[\"LocalTransformersEmbeddingProvider\"],\n\t\t\tChromaVectorStore: chroma.ChromaVectorStore as AiRagModules[\"ChromaVectorStore\"],\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`--embedding-provider local / --*-backend=chroma require @melandlabs/ai-rag to be installed. Run \\`pnpm add @melandlabs/ai-rag\\` and try again. (${(error as Error).message})`,\n\t\t);\n\t}\n}\n\nexport function parseUnifiedArgs(argv: string[]): UnifiedArgs {\n\tconst env = process.env;\n\tconst args: UnifiedArgs = {\n\t\tembeddingProvider: (env.EMBEDDING_PROVIDER as UnifiedArgs[\"embeddingProvider\"] | undefined) ?? \"none\",\n\t\tembeddingModel: env.EMBEDDING_MODEL,\n\t\tchromaUrl: env.CHROMA_URL,\n\t\tmemoryBackend: (env.MEMORY_BACKEND as UnifiedArgs[\"memoryBackend\"] | undefined) ?? \"none\",\n\t\tinsightsBackend: (env.INSIGHTS_BACKEND as UnifiedArgs[\"insightsBackend\"] | undefined) ?? \"none\",\n\t\tinsightsCollection: env.INSIGHTS_COLLECTION ?? \"opencontext_insights\",\n\t\tknowledgeBackend: (env.KNOWLEDGE_BACKEND as UnifiedArgs[\"knowledgeBackend\"] | undefined) ?? \"none\",\n\t\tknowledgeCollection: env.KNOWLEDGE_COLLECTION ?? \"opencontext_knowledge\",\n\t};\n\tfor (let i = 0; i < argv.length; i += 1) {\n\t\tconst arg = argv[i];\n\t\tconst next = argv[i + 1];\n\t\tconst takeValue = () => {\n\t\t\tif (next === undefined) throw new Error(`[memory-store/http] ${arg} requires a value`);\n\t\t\ti += 1;\n\t\t\treturn next;\n\t\t};\n\t\tswitch (arg) {\n\t\t\tcase \"--embedding-provider\":\n\t\t\t\targs.embeddingProvider = takeValue() as UnifiedArgs[\"embeddingProvider\"];\n\t\t\t\tbreak;\n\t\t\tcase \"--embedding-model\":\n\t\t\t\targs.embeddingModel = takeValue();\n\t\t\t\tbreak;\n\t\t\tcase \"--chroma-url\":\n\t\t\t\targs.chromaUrl = takeValue();\n\t\t\t\tbreak;\n\t\t\tcase \"--memory-backend\":\n\t\t\t\targs.memoryBackend = takeValue() as UnifiedArgs[\"memoryBackend\"];\n\t\t\t\tbreak;\n\t\t\tcase \"--insights-backend\":\n\t\t\t\targs.insightsBackend = takeValue() as UnifiedArgs[\"insightsBackend\"];\n\t\t\t\tbreak;\n\t\t\tcase \"--insights-collection\":\n\t\t\t\targs.insightsCollection = takeValue();\n\t\t\t\tbreak;\n\t\t\tcase \"--knowledge-backend\":\n\t\t\t\targs.knowledgeBackend = takeValue() as UnifiedArgs[\"knowledgeBackend\"];\n\t\t\t\tbreak;\n\t\t\tcase \"--knowledge-collection\":\n\t\t\t\targs.knowledgeCollection = takeValue();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tfor (const [name, value] of [\n\t\t[\"--embedding-provider\", args.embeddingProvider],\n\t\t[\"--memory-backend\", args.memoryBackend],\n\t\t[\"--insights-backend\", args.insightsBackend],\n\t\t[\"--knowledge-backend\", args.knowledgeBackend],\n\t] as const) {\n\t\tconst allowed = [\"local\", \"openrouter\", \"none\", \"chroma\", \"sqlite-vec\"];\n\t\tif (!(allowed as readonly string[]).includes(value)) {\n\t\t\tthrow new Error(`[memory-store/cli] ${name} must be one of: ${allowed.join(\", \")} (got \"${value}\")`);\n\t\t}\n\t}\n\treturn args;\n}\n\nexport async function buildUnified(args: UnifiedArgs): Promise<UnifiedSearchDeps> {\n\tconst unified: UnifiedSearchDeps = {};\n\tconst log = (msg: string) => console.warn(`[memory-store/cli] ${msg}`);\n\n\tconst wantsAiRag =\n\t\targs.embeddingProvider === \"local\" ||\n\t\targs.memoryBackend === \"chroma\" ||\n\t\targs.insightsBackend === \"chroma\" ||\n\t\targs.knowledgeBackend === \"chroma\";\n\tconst aiRag = wantsAiRag ? await loadAiRag() : null;\n\n\t// ── 1. Wire the embedder (if any) — must happen before any backend\n\t// that consults it.\n\tif (args.embeddingProvider === \"local\") {\n\t\tconst provider = new aiRag!.LocalTransformersEmbeddingProvider({ modelName: args.embeddingModel });\n\t\tunified.embedQuery = async ({ query }) => provider.embedQuery(query);\n\t\tlog(\n\t\t\t`embedQuery wired via LocalTransformersEmbeddingProvider (model=${args.embeddingModel ?? \"Xenova/all-MiniLM-L6-v2\"})`,\n\t\t);\n\t} else if (args.embeddingProvider === \"openrouter\") {\n\t\tconst apiKey = process.env.OPENROUTER_API_KEY;\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\"--embedding-provider openrouter requires OPENROUTER_API_KEY in the environment\");\n\t\t}\n\t\tconst model = args.embeddingModel ?? \"text-embedding-3-small\";\n\t\tconst baseURL = \"https://openrouter.ai/api/v1\";\n\t\tunified.embedQuery = async ({ query }) => {\n\t\t\tconst res = await fetch(`${baseURL}/embeddings`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\tauthorization: `Bearer ${apiKey}`,\n\t\t\t\t\t\"HTTP-Referer\": process.env.NEXT_PUBLIC_APP_URL ?? \"https://opencontext.ai\",\n\t\t\t\t\t\"X-Title\": \"opencontext AI\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ model, input: query }),\n\t\t\t});\n\t\t\tif (!res.ok) {\n\t\t\t\tthrow new Error(`openrouter embeddings ${res.status}: ${await res.text()}`);\n\t\t\t}\n\t\t\tconst body = (await res.json()) as { data: Array<{ embedding: number[] }> };\n\t\t\tconst embedding = body.data?.[0]?.embedding;\n\t\t\tif (!embedding) throw new Error(\"openrouter embeddings response missing data[0].embedding\");\n\t\t\treturn embedding;\n\t\t};\n\t\tlog(`embedQuery wired via openrouter (model=${model})`);\n\t}\n\n\t// ── 2. Wire the memory source backend.\n\tif (args.memoryBackend === \"sqlite-vec\") {\n\t\tconst store = createRawMessageStore({ env: undefined });\n\t\tconst manager = await store.getManager();\n\t\tif (typeof manager.searchMessagesSemantically !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"the active raw-message manager does not implement searchMessagesSemantically; \" +\n\t\t\t\t\t\"sqlite-vec ANN for the memory source is unavailable in this build\",\n\t\t\t);\n\t\t}\n\t\tunified.searchRawMessagesAnn = async ({ userId, queryEmbedding, limit, threshold, botId }) => {\n\t\t\tconst rows = (await manager.searchMessagesSemantically!({\n\t\t\t\tuserId,\n\t\t\t\tqueryEmbedding,\n\t\t\t\tlimit,\n\t\t\t\tthreshold,\n\t\t\t\tbotId,\n\t\t\t})) as Array<{ id: string; content: string; similarity: number; metadata?: Record<string, unknown> }>;\n\t\t\treturn rows.map((r) => ({\n\t\t\t\tid: r.id,\n\t\t\t\tcontent: r.content,\n\t\t\t\tsimilarity: r.similarity,\n\t\t\t\tmetadata: r.metadata ?? {},\n\t\t\t}));\n\t\t};\n\t\tlog(\"memory backend wired via sqlite-vec (uses the manager's searchMessagesSemantically)\");\n\t} else if (args.memoryBackend === \"chroma\") {\n\t\tif (!args.chromaUrl)\n\t\t\tthrow new Error(\"--memory-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)\");\n\t\tconst store = new aiRag!.ChromaVectorStore({\n\t\t\turl: args.chromaUrl,\n\t\t\tcollectionName: \"opencontext_raw_messages\",\n\t\t});\n\t\tunified.searchRawMessagesAnn = async ({ queryEmbedding, limit, threshold }) => {\n\t\t\tconst results = await store.similaritySearchWithOptions(queryEmbedding, { limit: limit + 1 });\n\t\t\treturn results\n\t\t\t\t.filter((r) => r.score >= threshold)\n\t\t\t\t.map((r) => ({ id: r.id, content: r.content, similarity: r.score, metadata: r.metadata ?? {} }));\n\t\t};\n\t\tlog(\"memory backend wired via chroma (collection=opencontext_raw_messages)\");\n\t}\n\n\t// ── 3. Wire the insights source backend.\n\tif (args.insightsBackend === \"sqlite-vec\" && isInsightSQLiteVecEnabled()) {\n\t\tif (!unified.embedQuery) {\n\t\t\tthrow new Error(\"--insights-backend=sqlite-vec requires --embedding-provider local|openrouter\");\n\t\t}\n\t\tconst embedQuery = unified.embedQuery;\n\t\tunified.searchInsights = async ({ userId, query, limit, threshold, botIds, includeArchived }) => {\n\t\t\tconst emb = await embedQuery({ userId, query });\n\t\t\tconst rows = await searchInsightsWithSQLiteVec({\n\t\t\t\tuserId,\n\t\t\t\tqueryEmbedding: emb,\n\t\t\t\tlimit,\n\t\t\t\tthreshold,\n\t\t\t\tbotIds,\n\t\t\t\tincludeArchived,\n\t\t\t});\n\t\t\treturn rows.map((r) => ({\n\t\t\t\tid: r.id,\n\t\t\t\tcontent: r.content,\n\t\t\t\tsimilarity: r.score,\n\t\t\t\tmetadata: r.metadata ?? {},\n\t\t\t}));\n\t\t};\n\t\tlog(\"insights backend wired via sqlite-vec\");\n\t} else if (args.insightsBackend === \"chroma\") {\n\t\tif (!args.chromaUrl)\n\t\t\tthrow new Error(\"--insights-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)\");\n\t\tif (!unified.embedQuery)\n\t\t\tthrow new Error(\"--insights-backend=chroma requires --embedding-provider local|openrouter\");\n\t\tconst store = new aiRag!.ChromaVectorStore({\n\t\t\turl: args.chromaUrl,\n\t\t\tcollectionName: args.insightsCollection,\n\t\t});\n\t\tconst embedQuery = unified.embedQuery;\n\t\tunified.searchInsights = async ({ query, limit, threshold }) => {\n\t\t\tconst emb = await embedQuery({ userId: \"\", query });\n\t\t\tconst results = await store.similaritySearchWithOptions(emb, { limit: limit + 1 });\n\t\t\treturn results\n\t\t\t\t.filter((r) => r.score >= threshold)\n\t\t\t\t.map((r) => ({ id: r.id, content: r.content, similarity: r.score, metadata: r.metadata ?? {} }));\n\t\t};\n\t\tlog(`insights backend wired via chroma (collection=${args.insightsCollection})`);\n\t}\n\n\t// ── 4. Wire the knowledge source backend.\n\tif (args.knowledgeBackend === \"chroma\") {\n\t\tif (!args.chromaUrl)\n\t\t\tthrow new Error(\"--knowledge-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)\");\n\t\tif (!unified.embedQuery)\n\t\t\tthrow new Error(\"--knowledge-backend=chroma requires --embedding-provider local|openrouter\");\n\t\tconst store = new aiRag!.ChromaVectorStore({\n\t\t\turl: args.chromaUrl,\n\t\t\tcollectionName: args.knowledgeCollection,\n\t\t});\n\t\tconst embedQuery = unified.embedQuery;\n\t\tunified.searchKnowledge = async ({ query, options }) => {\n\t\t\tconst emb = await embedQuery({ userId: \"\", query });\n\t\t\tconst results = await store.similaritySearchWithOptions(emb, { limit: options.limit + 1 });\n\t\t\treturn results\n\t\t\t\t.filter((r) => r.score >= options.threshold)\n\t\t\t\t.map((r, i) => ({\n\t\t\t\t\tchunkId: r.id,\n\t\t\t\t\tdocumentId: r.documentId || String(r.metadata?.documentId ?? r.id),\n\t\t\t\t\tdocumentName: String(r.metadata?.documentName ?? \"\"),\n\t\t\t\t\tcontent: r.content,\n\t\t\t\t\tsimilarity: r.score,\n\t\t\t\t\tchunkIndex: i,\n\t\t\t\t}));\n\t\t};\n\t\tlog(`knowledge backend wired via chroma (collection=${args.knowledgeCollection})`);\n\t}\n\n\treturn unified;\n}\n\n/**\n * Subcommand-agnostic help text used by `cli-http --help` and\n * `cli-mcp --help`. The caller prepends the bin-specific intro\n * (server-only flags like `--port`/`--host`).\n */\nexport function printUnifiedHelp(): void {\n\tconsole.log(`Embedding (wires unified.embedQuery):\n --embedding-provider <name> local | openrouter | none\n (env: EMBEDDING_PROVIDER, default: none)\n --embedding-model <name> Model name\n (env: EMBEDDING_MODEL; local → Xenova/all-MiniLM-L6-v2,\n openrouter → text-embedding-3-small)\n Note: \"local\" dynamically imports @melandlabs/ai-rag (a peer install).\n\nCross-source search (wires unified.searchKnowledge / searchInsights / searchRawMessagesAnn):\n --chroma-url <url> Chroma server URL\n (env: CHROMA_URL; required when any *-backend=chroma)\n --memory-backend <name> sqlite-vec | chroma | none\n (env: MEMORY_BACKEND, default: none)\n --insights-backend <name> sqlite-vec | chroma | none\n (env: INSIGHTS_BACKEND, default: none)\n --insights-collection <name> Chroma collection (default: opencontext_insights)\n --knowledge-backend <name> chroma | none\n (env: KNOWLEDGE_BACKEND, default: none)\n --knowledge-collection <name> Chroma collection (default: opencontext_knowledge)\n Note: the chroma backends dynamically import @melandlabs/ai-rag.`);\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/contracts.ts","../../src/storage/chroma-memory-index.ts"],"names":["normalizeTimestampToMs"],"mappings":"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","file":"chroma-memory-index.js","sourcesContent":["/**\n * Memory-store contracts — types and constants that were originally re-exported\n * from `@melandlabs/indexeddb` but pulled in browser-only code (IndexedDB\n * globals) at module evaluation time, breaking the standalone HTTP/MCP\n * daemons.\n *\n * Anything defined here can be safely imported on the server without any\n * browser globals being resolved. The `@melandlabs/indexeddb` peer dependency\n * is optional in `@melandlabs/memory-store/package.json`; consumers can\n * depend on it directly for IndexedDB-backed storage.\n *\n * Re-export from this module is stable. New domain types belong in\n * dedicated files; this module only hosts the boundary contracts.\n */\n\nimport type { MemoryRecord } from \"@melandlabs/ai/memory\";\n\n/** Prefix used to reserve chat-memory evidence IDs that must not collide. */\nexport const CHAT_MEMORY_EVIDENCE_ID_PREFIX = \"opencontext-chat:\";\n\n/** A locally-defined re-export of the raw-message shape used by the SDK.\n * Kept as a structural type so consumers (SQLite, postgres factories)\n * can pass either the IndexedDB `RawMessage` or this shape. */\n// biome-ignore lint/suspicious/noExplicitAny: structural mirror of `@melandlabs/indexeddb/storage`'s `RawMessage`.\nexport interface RawMessage {\n\tid?: number;\n\tmessageId: string;\n\tplatform: string;\n\tbotId: string;\n\tuserId: string;\n\tchannel?: string;\n\tperson?: string;\n\ttimestamp: number;\n\tcontent: string;\n\tattachments?: Array<{\n\t\tname: string;\n\t\turl: string;\n\t\tcontentType?: string;\n\t\tsizeBytes?: number;\n\t}>;\n\tembedding?: number[];\n\tembeddingModel?: string;\n\tembeddingContentHash?: string;\n\tembeddingDimensions?: number;\n\tembeddingUpdatedAt?: number;\n\t// biome-ignore lint/suspicious/noExplicitAny: Preserve the public raw metadata contract.\n\tmetadata?: Record<string, any>;\n\tcreatedAt: number;\n\tmemoryStage?: \"short\" | \"mid\" | \"long\";\n\taccessCount?: number;\n\tlastAccessAt?: number;\n\timportanceScore?: number;\n\tarchivedAt?: number;\n\tisPinned?: boolean;\n\tsummaryRefId?: string;\n\tdeprecatedAt?: number;\n\tdeprecationReason?: string;\n\tsupersededBySummaryId?: string;\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\n/** Convert a RawMessage to a MemoryRecord for embedding. Local copy of the\n * helper that previously lived in `@melandlabs/indexeddb/embedding` and pulled\n * in browser-only modules. */\nexport function rawMessageToMemoryRecord(message: RawMessage): MemoryRecord {\n\treturn {\n\t\tid: message.messageId,\n\t\tuserId: message.userId,\n\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\ttext: message.archivedAt ? undefined : message.content,\n\t\tmediaRefs: message.attachments?.map((item) => item.url).filter(Boolean),\n\t\tembedding: message.embedding,\n\t\tembeddingModel: message.embeddingModel,\n\t\tembeddingContentHash: message.embeddingContentHash,\n\t} as unknown as MemoryRecord;\n}\n","/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/postgres-raw-message-factory.ts"],"names":[],"mappings":";AA4CA,IAAI,OAAA,GAAoC,IAAA;AAEjC,SAAS,wBAAwB,EAAA,EAA6B;AACpE,EAAA,OAAA,GAAU,EAAA;AACX;AAEO,SAAS,oBAAA,GAA6B;AAC5C,EAAA,OAAA,GAAU,IAAA;AACX;AAEA,eAAsB,uBACrB,GAAA,EACgD;AAChD,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,OAAO,MAAM,QAAQ,GAAG,CAAA;AACzB;AAEO,SAAS,kBAAA,GAA8B;AAC7C,EAAA,OAAO,OAAA,KAAY,IAAA;AACpB","file":"postgres-raw-message-factory.js","sourcesContent":["/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/postgres-raw-message-factory.ts","../../src/storage/chroma-memory-index.ts","../../src/storage/sqlite-raw-message-store.ts","../../src/storage/raw-message-store.ts"],"names":[],"mappings":"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","file":"raw-message-store.js","sourcesContent":["/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n","/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n","/**\n * Top-level raw-message store facade.\n *\n * Backend selection is env-var driven:\n *\n * - `OPENCONTEXT_MEMORY_STORE_BACKEND=postgres` → use the host's\n * registered Postgres factory. A factory MUST be registered first\n * via `registerPostgresFactory()`; otherwise this throws a clear\n * error rather than silently falling back.\n * - Any other value (including unset) → local SQLite. The default\n * works in every host environment with no extra configuration.\n *\n * The facade exposes the common `RawMessageStorageManager` contract plus\n * a typed `searchMessagesSemantically` extension when present.\n */\n\nimport type { RawMessageStorageManager } from \"@melandlabs/indexeddb/storage\";\nimport type { MemoryStoreConfig, MemoryStoreEnv } from \"../config\";\nimport { hasPostgresFactory, resolvePostgresFactory } from \"./postgres-raw-message-factory\";\nimport { closeSQLiteRawMessageManager, getSQLiteRawMessageManager } from \"./sqlite-raw-message-store\";\n\nexport type RawMessageStorageBackend = \"sqlite\" | \"postgres\";\n\nexport type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {\n\tsearchMessagesSemantically?: (input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}) => Promise<unknown[]>;\n};\n\nexport interface CreateRawMessageStoreOptions {\n\tenv?: MemoryStoreEnv;\n}\n\nexport interface RawMessageStore {\n\tgetManager(): Promise<RawMessageStorageManagerWithSearch>;\n\tgetBackend(): RawMessageStorageBackend;\n\tisAvailable(): boolean;\n\tclose(): Promise<void>;\n}\n\nfunction resolveBackend(env: MemoryStoreEnv | undefined): RawMessageStorageBackend {\n\tconst explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();\n\tif (explicit === \"postgres\") return \"postgres\";\n\t// Any other value — including the default \"sqlite\", an unknown value,\n\t// or the env var being unset — falls through to local SQLite.\n\treturn \"sqlite\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nexport function createRawMessageStore(options: CreateRawMessageStoreOptions = {}): RawMessageStore {\n\tconst env = resolveEnv(options.env);\n\n\treturn {\n\t\tgetBackend(): RawMessageStorageBackend {\n\t\t\treturn resolveBackend(env);\n\t\t},\n\t\tisAvailable(): boolean {\n\t\t\t// SQLite is always available; postgres is only available when the\n\t\t\t// env var asks for it AND a factory has been registered.\n\t\t\treturn resolveBackend(env) === \"sqlite\" || hasPostgresFactory();\n\t\t},\n\t\tasync getManager(): Promise<RawMessageStorageManagerWithSearch> {\n\t\t\tif (resolveBackend(env) === \"postgres\") {\n\t\t\t\tconst pg = await resolvePostgresFactory(env);\n\t\t\t\tif (!pg) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"OPENCONTEXT_MEMORY_STORE_BACKEND=postgres but no Postgres factory is registered. \" +\n\t\t\t\t\t\t\t\"Call registerPostgresFactory() at startup, or unset the env var to use the default SQLite backend.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn pg as unknown as RawMessageStorageManagerWithSearch;\n\t\t\t}\n\t\t\treturn (await getSQLiteRawMessageManager(env)) as unknown as RawMessageStorageManagerWithSearch;\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\t// The sqlite singleton is process-wide, so close regardless of the\n\t\t\t// env var's current value — the previous call may have used it.\n\t\t\tawait closeSQLiteRawMessageManager();\n\t\t},\n\t};\n}\n\n// Module-level singleton so existing call sites that imported the\n// legacy `getRawMessageManager()` keep working without a refactor.\nlet moduleStore: RawMessageStore | null = null;\nlet moduleConfig: MemoryStoreConfig | null = null;\n\nexport function configureRawMessageStore(config: MemoryStoreConfig): RawMessageStore {\n\tmoduleConfig = config;\n\tmoduleStore = createRawMessageStore({ env: config.env });\n\treturn moduleStore;\n}\n\nexport function getRawMessageStorageBackend(): RawMessageStorageBackend {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getBackend();\n}\n\nexport function isRawMessageStorageAvailable(): boolean {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.isAvailable();\n}\n\nexport async function getRawMessageManager(): Promise<RawMessageStorageManagerWithSearch> {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getManager();\n}\n\nexport async function closeRawMessageStore(): Promise<void> {\n\tif (!moduleStore) return;\n\tawait moduleStore.close();\n\tmoduleStore = null;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/chroma-memory-index.ts","../../src/storage/sqlite-raw-message-store.ts"],"names":[],"mappings":";;;;;;;;AAiBA,IAAM,2BAAA,GAA8B;AAAA,EACnC,kCAAA;AAAA,EACA,6BAAA;AAAA,EACA;AACD,CAAA;AA+CA,SAAS,WAAW,IAAA,EAAiC;AACpD,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACvB,IAAA,MAAM,QAAQ,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG,IAAA,GAAO,WAAA,EAAY;AACnD,IAAA,IAAI,KAAA,EAAO;AACV,MAAA,OAAO,KAAA;AAAA,IACR;AAAA,EACD;AACA,EAAA,OAAO,EAAA;AACR;AAEO,SAAS,yBAAA,GAAqC;AACpD,EAAA,OAAO,UAAA,CAAW,2BAA2B,CAAA,KAAM,QAAA;AACpD;;;AC5DA,IAAI,OAAA,GAA0C,IAAA;AAE9C,IAAM,sBAAsB,IAAA,CAAK,OAAA,EAAQ,EAAG,cAAA,EAAgB,UAAU,UAAU,CAAA;AAMzE,SAAS,6BAAA,GAAwC;AACvD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,oBAAA,EAAsB,IAAA,EAAK;AACvD,EAAA,OAAO,OAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,GAAI,OAAA,GAAU,mBAAA;AAClD;AAMO,SAAS,mCAAmC,IAAA,EAAgC;AAClF,EAAA,OAAO,IAAA;AACR;AAEA,eAAsB,2BAA2B,IAAA,EAAyD;AACzG,EAAA,IAAI,CAAC,OAAA,EAAS;AACb,IAAA,MAAM,SAAS,6BAAA,EAA8B;AAC7C,IAAA,SAAA,CAAU,QAAQ,MAAM,CAAA,EAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC9C,IAAA,OAAA,GAAU,IAAI,uBAAA,CAAwB;AAAA,MACrC,MAAA;AAAA,MACA,kBAAA,EAAoB,CAAC,yBAAA;AAA0B,KAC/C,CAAA;AACD,IAAA,MAAM,QAAQ,IAAA,EAAK;AAAA,EACpB;AAEA,EAAA,OAAO,OAAA;AACR;AAEA,eAAsB,4BAAA,GAA8C;AACnE,EAAA,IAAI,CAAC,OAAA,EAAS;AACb,IAAA;AAAA,EACD;AACA,EAAA,MAAM,QAAQ,KAAA,EAAM;AACpB,EAAA,OAAA,GAAU,IAAA;AACX;AAKO,SAAS,sCAAA,GAA+C;AAC9D,EAAA,OAAA,GAAU,IAAA;AACX","file":"sqlite-raw-message-store.js","sourcesContent":["/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/storage/sqlite-raw-message-store.ts","../../src/storage/sqlite-vector-index.ts"],"names":[],"mappings":"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","file":"sqlite-vector-index.js","sourcesContent":["/**\n * SQLite-backed raw message store.\n *\n * Singleton manager. Local SQLite is the default backend for the memory\n * store — no host-mode check, no env-var opt-in. The DB path is resolved\n * from (in order):\n * 1. `MEMORY_STORE_DB_PATH` — recommended knob\n * 2. `~/.opencontext/memory/store.db` — last-resort default\n *\n * The `env?` parameter on the exported functions is kept for back-compat\n * with the historical `MemoryStoreEnv` interface but is no longer read.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nconst DEFAULT_SQLITE_PATH = join(homedir(), \".opencontext\", \"memory\", \"store.db\");\n\n/**\n * Resolve the SQLite DB file path from env vars. Exposed so other storage\n * layers (vector index) can stay in sync with the same default.\n */\nexport function resolveSQLiteRawMessageDbPath(): string {\n\tconst fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();\n\treturn fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;\n}\n\n/**\n * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can\n * open the manager; the only failure mode is filesystem write permission.\n */\nexport function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean {\n\treturn true;\n}\n\nexport async function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tif (!manager) {\n\t\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\n// Kept for back-compat with the historical `MemoryStoreEnv` interface.\n// The resolved env is no longer read by the SQLite layer, but the symbol\n// stays exported so external code that still calls `resolveEnv` compiles.\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n","/**\n * SQLite-vec-backed raw-message + insight vector index.\n *\n * Mirrors the chroma-memory-index interface but uses the local\n * sqlite-vec store. The DB path is resolved from the same env-var chain\n * the raw-message SQLite layer uses.\n */\n\nimport type { VectorSearchResult } from \"@melandlabs/rag/vector-service\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { resolveSQLiteRawMessageDbPath } from \"./sqlite-raw-message-store\";\n\nexport interface SQLiteInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface SQLiteInsightSearchInput {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}\n\nfunction getMemoryVectorStoreBackend(): \"chroma\" | \"sqlite-vec\" {\n\tconst backend = (\n\t\tprocess.env.INSIGHT_VECTOR_STORE_BACKEND ||\n\t\tprocess.env.MEMORY_VECTOR_STORE_BACKEND ||\n\t\tprocess.env.VECTOR_STORE_BACKEND ||\n\t\t\"sqlite-vec\"\n\t).toLowerCase();\n\treturn backend === \"chroma\" ? \"chroma\" : \"sqlite-vec\";\n}\n\nexport function isInsightSQLiteVecEnabled(_env?: MemoryStoreEnv): boolean {\n\treturn getMemoryVectorStoreBackend() === \"sqlite-vec\";\n}\n\nfunction resolveEnv(_env?: MemoryStoreEnv): MemoryStoreEnv {\n\treturn {};\n}\n\nasync function getInsightSQLiteVecStore(_env: MemoryStoreEnv) {\n\tconst dbPath = resolveSQLiteRawMessageDbPath();\n\tconst { getSQLiteVecStore } = await import(\"@melandlabs/rag/sqlite-vec-store\");\n\treturn await getSQLiteVecStore(dbPath, undefined, {\n\t\tcollectionName: process.env.SQLITE_VEC_INSIGHTS_COLLECTION || \"opencontext_insights\",\n\t});\n}\n\nexport async function upsertInsightsToSQLiteVec(\n\tinsights: SQLiteInsightVectorInput[],\n\tenv?: MemoryStoreEnv,\n): Promise<number> {\n\tif (!isInsightSQLiteVecEnabled(env) || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = await getInsightSQLiteVecStore(resolveEnv(env));\n\tawait store.addChunks(\n\t\tinsights.map((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: normalizeTime(item.time),\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t})),\n\t);\n\treturn insights.length;\n}\n\nexport async function searchInsightsWithSQLiteVec(\n\tinput: SQLiteInsightSearchInput,\n\tenv?: MemoryStoreEnv,\n): Promise<VectorSearchResult[]> {\n\tconst store = await getInsightSQLiteVecStore(resolveEnv(env));\n\tconst overfetchLimit = Math.max(input.limit * 8, input.limit);\n\tconst results = await store.similaritySearchWithOptions(input.queryEmbedding, {\n\t\tlimit: overfetchLimit,\n\t\tfilter: { userId: input.userId },\n\t});\n\n\treturn results\n\t\t.filter((result) => result.score >= input.threshold)\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (input.botIds?.length && !input.botIds.includes(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn input.includeArchived || metadata.archived !== true;\n\t\t})\n\t\t.slice(0, input.limit);\n}\n\nfunction normalizeTime(value: unknown): number | null {\n\tif (value instanceof Date) return value.getTime();\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\") {\n\t\tconst parsed = Date.parse(value);\n\t\treturn Number.isFinite(parsed) ? parsed : null;\n\t}\n\treturn null;\n}\n\nfunction toStringValue(value: unknown): string {\n\treturn typeof value === \"string\" ? value : \"\";\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n"]}
|