teleton 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/{chunk-5FNWBZ5K.js → chunk-2IZU3REP.js} +147 -82
  2. package/dist/chunk-3UFPFWYP.js +12 -0
  3. package/dist/{chunk-KVXV7EF7.js → chunk-55SKE6YH.js} +2 -2
  4. package/dist/{setup-server-32XGDPE6.js → chunk-57URFK6M.js} +7 -206
  5. package/dist/chunk-5SEMA47R.js +75 -0
  6. package/dist/{chunk-S6PHGKOC.js → chunk-7YKSXOQQ.js} +10 -2
  7. package/dist/{chunk-UP55PXFH.js → chunk-C4NKJT2Z.js} +8 -0
  8. package/dist/{chunk-CGOXE4WP.js → chunk-GGXJLMOH.js} +404 -730
  9. package/dist/{chunk-QBHRXLZS.js → chunk-H7MFXJZK.js} +2 -2
  10. package/dist/{chunk-3S4GGLLR.js → chunk-HEDJCLA6.js} +58 -19
  11. package/dist/{chunk-AYWEJCDB.js → chunk-J73TA3UM.js} +7 -7
  12. package/dist/{chunk-QV2GLOTK.js → chunk-LC4TV3KL.js} +1 -1
  13. package/dist/{chunk-RCMD3U65.js → chunk-NQ6FZKCE.js} +13 -0
  14. package/dist/{chunk-7U7BOHCL.js → chunk-VYKW7FMV.js} +147 -63
  15. package/dist/chunk-W25Z7CM6.js +487 -0
  16. package/dist/{chunk-OJCLKU5Z.js → chunk-WFTC3JJW.js} +16 -0
  17. package/dist/{server-3FHI2SEB.js → chunk-XBSCYMKM.js} +23 -369
  18. package/dist/{chunk-PHSAHTK4.js → chunk-YOSUPUAJ.js} +75 -7
  19. package/dist/cli/index.js +61 -17
  20. package/dist/{client-MPHPIZB6.js → client-YOOHI776.js} +4 -4
  21. package/dist/{get-my-gifts-CC6HAVWB.js → get-my-gifts-Y7EN7RK4.js} +3 -3
  22. package/dist/index.js +14 -13
  23. package/dist/{memory-UBHM7ILG.js → memory-Q6EWGK2S.js} +6 -4
  24. package/dist/memory-hook-WUXJNVT5.js +18 -0
  25. package/dist/{migrate-UBBEJ5BL.js → migrate-WFU6COBN.js} +4 -4
  26. package/dist/server-GYZXKIKU.js +787 -0
  27. package/dist/server-YODFBZKG.js +392 -0
  28. package/dist/setup-server-IZBUOJRU.js +215 -0
  29. package/dist/{store-M5IMUQCL.js → store-7M4XV6M5.js} +5 -5
  30. package/dist/{task-dependency-resolver-RR2O5S7B.js → task-dependency-resolver-L6UUMTHK.js} +2 -2
  31. package/dist/{task-executor-6W5HRX5C.js → task-executor-XBNJLUCS.js} +2 -2
  32. package/dist/{tool-adapter-IH5VGBOO.js → tool-adapter-IVX2XQJE.js} +1 -1
  33. package/dist/{tool-index-PMAOXWUA.js → tool-index-NYH57UWP.js} +3 -3
  34. package/dist/{transcript-NGDPSNIH.js → transcript-IM7G25OS.js} +2 -2
  35. package/package.json +4 -2
  36. package/dist/chunk-XBE4JB7C.js +0 -8
@@ -3,20 +3,24 @@ import {
3
3
  createEmbeddingProvider,
4
4
  hashText,
5
5
  serializeEmbedding
6
- } from "./chunk-3S4GGLLR.js";
6
+ } from "./chunk-HEDJCLA6.js";
7
7
  import {
8
8
  FEED_MESSAGE_MAX_CHARS,
9
9
  HYBRID_SEARCH_MIN_SCORE,
10
10
  KNOWLEDGE_CHUNK_SIZE,
11
+ RECENCY_DECAY_FACTOR,
12
+ RECENCY_WEIGHT,
13
+ SECONDS_PER_DAY,
14
+ SECONDS_PER_HOUR,
11
15
  SQLITE_CACHE_SIZE_KB,
12
16
  SQLITE_MMAP_SIZE
13
- } from "./chunk-UP55PXFH.js";
17
+ } from "./chunk-C4NKJT2Z.js";
14
18
  import {
15
19
  TELETON_ROOT
16
20
  } from "./chunk-EYWNOHMJ.js";
17
21
  import {
18
22
  createLogger
19
- } from "./chunk-RCMD3U65.js";
23
+ } from "./chunk-NQ6FZKCE.js";
20
24
 
21
25
  // src/memory/database.ts
22
26
  import Database2 from "better-sqlite3";
@@ -456,9 +460,11 @@ function ensureVectorTables(db, dimensions) {
456
460
  WHERE type='table' AND name='knowledge_vec'
457
461
  `
458
462
  ).get();
463
+ let dimensionsChanged = false;
459
464
  if (existingDims?.sql && !existingDims.sql.includes(`[${dimensions}]`)) {
460
465
  db.exec(`DROP TABLE IF EXISTS knowledge_vec`);
461
466
  db.exec(`DROP TABLE IF EXISTS tg_messages_vec`);
467
+ dimensionsChanged = true;
462
468
  }
463
469
  db.exec(`
464
470
  CREATE VIRTUAL TABLE IF NOT EXISTS knowledge_vec USING vec0(
@@ -471,6 +477,7 @@ function ensureVectorTables(db, dimensions) {
471
477
  embedding FLOAT[${dimensions}] distance_metric=cosine
472
478
  );
473
479
  `);
480
+ return dimensionsChanged;
474
481
  }
475
482
  function getSchemaVersion(db) {
476
483
  const row = db.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get();
@@ -762,6 +769,7 @@ var MemoryDatabase = class {
762
769
  db;
763
770
  config;
764
771
  vectorReady = false;
772
+ _dimensionsChanged = false;
765
773
  constructor(config) {
766
774
  this.config = config;
767
775
  const dir = dirname2(config.path);
@@ -773,7 +781,8 @@ var MemoryDatabase = class {
773
781
  });
774
782
  try {
775
783
  chmodSync2(config.path, 384);
776
- } catch {
784
+ } catch (err) {
785
+ log3.warn({ err, path: config.path }, "Failed to set DB file permissions to 0o600");
777
786
  }
778
787
  this.db.pragma("journal_mode = WAL");
779
788
  this.db.pragma("synchronous = NORMAL");
@@ -787,7 +796,8 @@ var MemoryDatabase = class {
787
796
  let currentVersion = null;
788
797
  try {
789
798
  currentVersion = getSchemaVersion(this.db);
790
- } catch {
799
+ } catch (err) {
800
+ log3.warn({ err }, "Could not read schema version, assuming fresh database");
791
801
  currentVersion = null;
792
802
  }
793
803
  if (!currentVersion) {
@@ -806,7 +816,7 @@ var MemoryDatabase = class {
806
816
  sqliteVec.load(this.db);
807
817
  this.db.prepare("SELECT vec_version() as vec_version").get();
808
818
  const dims = this.config.vectorDimensions ?? 512;
809
- ensureVectorTables(this.db, dims);
819
+ this._dimensionsChanged = ensureVectorTables(this.db, dims);
810
820
  this.vectorReady = true;
811
821
  } catch (error) {
812
822
  log3.warn(`sqlite-vec not available, vector search disabled: ${error.message}`);
@@ -826,6 +836,9 @@ var MemoryDatabase = class {
826
836
  isVectorSearchReady() {
827
837
  return this.vectorReady;
828
838
  }
839
+ didDimensionsChange() {
840
+ return this._dimensionsChanged;
841
+ }
829
842
  getVectorDimensions() {
830
843
  return this.config.vectorDimensions;
831
844
  }
@@ -847,21 +860,24 @@ var MemoryDatabase = class {
847
860
  }
848
861
  }
849
862
  getStats() {
850
- const knowledge = this.db.prepare(`SELECT COUNT(*) as c FROM knowledge`).get();
851
- const sessions = this.db.prepare(`SELECT COUNT(*) as c FROM sessions`).get();
852
- const tasks = this.db.prepare(`SELECT COUNT(*) as c FROM tasks`).get();
853
- const tgChats = this.db.prepare(`SELECT COUNT(*) as c FROM tg_chats`).get();
854
- const tgUsers = this.db.prepare(`SELECT COUNT(*) as c FROM tg_users`).get();
855
- const tgMessages = this.db.prepare(`SELECT COUNT(*) as c FROM tg_messages`).get();
856
- const embeddingCache = this.db.prepare(`SELECT COUNT(*) as c FROM embedding_cache`).get();
863
+ const counts = this.db.prepare(
864
+ `SELECT
865
+ (SELECT COUNT(*) FROM knowledge) as knowledge,
866
+ (SELECT COUNT(*) FROM sessions) as sessions,
867
+ (SELECT COUNT(*) FROM tasks) as tasks,
868
+ (SELECT COUNT(*) FROM tg_chats) as tg_chats,
869
+ (SELECT COUNT(*) FROM tg_users) as tg_users,
870
+ (SELECT COUNT(*) FROM tg_messages) as tg_messages,
871
+ (SELECT COUNT(*) FROM embedding_cache) as embedding_cache`
872
+ ).get();
857
873
  return {
858
- knowledge: knowledge.c,
859
- sessions: sessions.c,
860
- tasks: tasks.c,
861
- tgChats: tgChats.c,
862
- tgUsers: tgUsers.c,
863
- tgMessages: tgMessages.c,
864
- embeddingCache: embeddingCache.c,
874
+ knowledge: counts.knowledge,
875
+ sessions: counts.sessions,
876
+ tasks: counts.tasks,
877
+ tgChats: counts.tg_chats,
878
+ tgUsers: counts.tg_users,
879
+ tgMessages: counts.tg_messages,
880
+ embeddingCache: counts.embedding_cache,
865
881
  vectorSearchEnabled: this.vectorReady
866
882
  };
867
883
  }
@@ -929,12 +945,12 @@ var KnowledgeIndexer = class {
929
945
  this.embedder = embedder;
930
946
  this.vectorEnabled = vectorEnabled;
931
947
  }
932
- async indexAll() {
948
+ async indexAll(options) {
933
949
  const files = this.listMemoryFiles();
934
950
  let indexed = 0;
935
951
  let skipped = 0;
936
952
  for (const file of files) {
937
- const wasIndexed = await this.indexFile(file);
953
+ const wasIndexed = await this.indexFile(file, options?.force);
938
954
  if (wasIndexed) {
939
955
  indexed++;
940
956
  } else {
@@ -943,16 +959,18 @@ var KnowledgeIndexer = class {
943
959
  }
944
960
  return { indexed, skipped };
945
961
  }
946
- async indexFile(absPath) {
962
+ async indexFile(absPath, force) {
947
963
  if (!existsSync3(absPath) || !absPath.endsWith(".md")) {
948
964
  return false;
949
965
  }
950
966
  const content = readFileSync(absPath, "utf-8");
951
967
  const relPath = absPath.replace(this.workspaceDir + "/", "");
952
968
  const fileHash = hashText(content);
953
- const existing = this.db.prepare(`SELECT hash FROM knowledge WHERE path = ? AND source = 'memory' LIMIT 1`).get(relPath);
954
- if (existing?.hash === fileHash) {
955
- return false;
969
+ if (!force) {
970
+ const existing = this.db.prepare(`SELECT hash FROM knowledge WHERE path = ? AND source = 'memory' LIMIT 1`).get(relPath);
971
+ if (existing?.hash === fileHash) {
972
+ return false;
973
+ }
956
974
  }
957
975
  const chunks = this.chunkMarkdown(content, relPath);
958
976
  const texts = chunks.map((c) => c.text);
@@ -981,7 +999,7 @@ var KnowledgeIndexer = class {
981
999
  serializeEmbedding(embedding),
982
1000
  chunk.startLine,
983
1001
  chunk.endLine,
984
- chunk.hash
1002
+ fileHash
985
1003
  );
986
1004
  if (insertVec && embedding.length > 0) {
987
1005
  insertVec.run(chunk.id, serializeEmbedding(embedding));
@@ -1022,6 +1040,7 @@ var KnowledgeIndexer = class {
1022
1040
  let startLine = 1;
1023
1041
  let currentLine = 1;
1024
1042
  let inCodeBlock = false;
1043
+ let overlapPrefix = "";
1025
1044
  const flushChunk = () => {
1026
1045
  const text = currentChunk.trim();
1027
1046
  if (text.length > 0) {
@@ -1034,8 +1053,10 @@ var KnowledgeIndexer = class {
1034
1053
  endLine: currentLine - 1,
1035
1054
  hash: hashText(text)
1036
1055
  });
1056
+ const nonEmpty = text.split("\n").filter((l) => l.trim());
1057
+ overlapPrefix = nonEmpty.length > 0 ? nonEmpty.slice(-2).join("\n") + "\n" : "";
1037
1058
  }
1038
- currentChunk = "";
1059
+ currentChunk = overlapPrefix;
1039
1060
  startLine = currentLine;
1040
1061
  };
1041
1062
  for (const line of lines) {
@@ -1559,6 +1580,33 @@ var UserStore = class {
1559
1580
 
1560
1581
  // src/memory/search/hybrid.ts
1561
1582
  var log5 = createLogger("Memory");
1583
+ var UNIT_SECONDS = {
1584
+ hour: SECONDS_PER_HOUR,
1585
+ day: SECONDS_PER_DAY,
1586
+ week: 7 * SECONDS_PER_DAY,
1587
+ month: 30 * SECONDS_PER_DAY
1588
+ };
1589
+ function parseTemporalIntent(query) {
1590
+ const now = Math.floor(Date.now() / 1e3);
1591
+ const lower = query.toLowerCase();
1592
+ const agoMatch = lower.match(/(\d+)\s*(day|hour|week|month)s?\s*ago/);
1593
+ if (agoMatch) {
1594
+ const n = parseInt(agoMatch[1], 10);
1595
+ return { afterTimestamp: now - n * (UNIT_SECONDS[agoMatch[2]] ?? SECONDS_PER_DAY) };
1596
+ }
1597
+ const lastNMatch = lower.match(/last\s+(\d+)\s*(day|hour|week|month)s?/);
1598
+ if (lastNMatch) {
1599
+ const n = parseInt(lastNMatch[1], 10);
1600
+ return { afterTimestamp: now - n * (UNIT_SECONDS[lastNMatch[2]] ?? SECONDS_PER_DAY) };
1601
+ }
1602
+ if (/\btoday\b/.test(lower)) return { afterTimestamp: now - SECONDS_PER_DAY };
1603
+ if (/\byesterday\b/.test(lower)) return { afterTimestamp: now - 2 * SECONDS_PER_DAY };
1604
+ if (/\blast\s+week\b/.test(lower)) return { afterTimestamp: now - 7 * SECONDS_PER_DAY };
1605
+ if (/\bthis\s+week\b/.test(lower)) return { afterTimestamp: now - 7 * SECONDS_PER_DAY };
1606
+ if (/\blast\s+month\b/.test(lower)) return { afterTimestamp: now - 30 * SECONDS_PER_DAY };
1607
+ if (/\brecently?\b/.test(lower)) return { afterTimestamp: now - 3 * SECONDS_PER_DAY };
1608
+ return {};
1609
+ }
1562
1610
  function escapeFts5Query(query) {
1563
1611
  return query.replace(/["\*\-\+\(\)\:\^\~\?\.\@\#\$\%\&\!\[\]\{\}\|\\\/<>=,;'`]/g, " ").replace(/\s+/g, " ").trim();
1564
1612
  }
@@ -1579,8 +1627,18 @@ var HybridSearch = class {
1579
1627
  const limit = options.limit ?? 10;
1580
1628
  const vectorWeight = options.vectorWeight ?? 0.5;
1581
1629
  const keywordWeight = options.keywordWeight ?? 0.5;
1582
- const vectorResults = this.vectorEnabled ? this.vectorSearchMessages(queryEmbedding, Math.ceil(limit * 3), options.chatId) : [];
1583
- const keywordResults = this.keywordSearchMessages(query, Math.ceil(limit * 3), options.chatId);
1630
+ const vectorResults = this.vectorEnabled ? this.vectorSearchMessages(
1631
+ queryEmbedding,
1632
+ Math.ceil(limit * 3),
1633
+ options.chatId,
1634
+ options.afterTimestamp
1635
+ ) : [];
1636
+ const keywordResults = this.keywordSearchMessages(
1637
+ query,
1638
+ Math.ceil(limit * 3),
1639
+ options.chatId,
1640
+ options.afterTimestamp
1641
+ );
1584
1642
  return this.mergeResults(vectorResults, keywordResults, vectorWeight, keywordWeight, limit);
1585
1643
  }
1586
1644
  vectorSearchKnowledge(embedding, limit) {
@@ -1589,7 +1647,7 @@ var HybridSearch = class {
1589
1647
  const embeddingBuffer = serializeEmbedding(embedding);
1590
1648
  const rows = this.db.prepare(
1591
1649
  `
1592
- SELECT kv.id, k.text, k.source, kv.distance
1650
+ SELECT kv.id, k.text, k.source, kv.distance, k.created_at
1593
1651
  FROM (
1594
1652
  SELECT id, distance
1595
1653
  FROM knowledge_vec
@@ -1603,7 +1661,8 @@ var HybridSearch = class {
1603
1661
  text: row.text,
1604
1662
  source: row.source,
1605
1663
  score: 1 - row.distance,
1606
- vectorScore: 1 - row.distance
1664
+ vectorScore: 1 - row.distance,
1665
+ createdAt: row.created_at ?? void 0
1607
1666
  }));
1608
1667
  } catch (error) {
1609
1668
  log5.error({ err: error }, "Vector search error (knowledge)");
@@ -1616,7 +1675,7 @@ var HybridSearch = class {
1616
1675
  try {
1617
1676
  const rows = this.db.prepare(
1618
1677
  `
1619
- SELECT k.id, k.text, k.source, rank as score
1678
+ SELECT k.id, k.text, k.source, rank as score, k.created_at
1620
1679
  FROM knowledge_fts kf
1621
1680
  JOIN knowledge k ON k.rowid = kf.rowid
1622
1681
  WHERE knowledge_fts MATCH ?
@@ -1626,72 +1685,82 @@ var HybridSearch = class {
1626
1685
  ).all(safeQuery, limit);
1627
1686
  return rows.map((row) => ({
1628
1687
  ...row,
1629
- keywordScore: this.bm25ToScore(row.score)
1688
+ keywordScore: this.bm25ToScore(row.score),
1689
+ createdAt: row.created_at ?? void 0
1630
1690
  }));
1631
1691
  } catch (error) {
1632
1692
  log5.error({ err: error }, "FTS5 search error (knowledge)");
1633
1693
  return [];
1634
1694
  }
1635
1695
  }
1636
- vectorSearchMessages(embedding, limit, chatId) {
1696
+ vectorSearchMessages(embedding, limit, chatId, afterTimestamp) {
1637
1697
  if (!this.vectorEnabled || embedding.length === 0) return [];
1638
1698
  try {
1639
1699
  const embeddingBuffer = serializeEmbedding(embedding);
1640
- const sql = chatId ? `
1641
- SELECT mv.id, m.text, m.chat_id as source, mv.distance
1642
- FROM (
1643
- SELECT id, distance
1644
- FROM tg_messages_vec
1645
- WHERE embedding MATCH ? AND k = ?
1646
- ) mv
1647
- JOIN tg_messages m ON m.id = mv.id
1648
- WHERE m.chat_id = ?
1649
- ` : `
1650
- SELECT mv.id, m.text, m.chat_id as source, mv.distance
1700
+ const conditions = [];
1701
+ const params = [embeddingBuffer, limit];
1702
+ if (chatId) {
1703
+ conditions.push("m.chat_id = ?");
1704
+ params.push(chatId);
1705
+ }
1706
+ if (afterTimestamp) {
1707
+ conditions.push("m.timestamp >= ?");
1708
+ params.push(afterTimestamp);
1709
+ }
1710
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1711
+ const sql = `
1712
+ SELECT mv.id, m.text, m.chat_id as source, mv.distance, m.timestamp
1651
1713
  FROM (
1652
1714
  SELECT id, distance
1653
1715
  FROM tg_messages_vec
1654
1716
  WHERE embedding MATCH ? AND k = ?
1655
1717
  ) mv
1656
1718
  JOIN tg_messages m ON m.id = mv.id
1719
+ ${whereClause}
1657
1720
  `;
1658
- const rows = chatId ? this.db.prepare(sql).all(embeddingBuffer, limit, chatId) : this.db.prepare(sql).all(embeddingBuffer, limit);
1721
+ const rows = this.db.prepare(sql).all(...params);
1659
1722
  return rows.map((row) => ({
1660
1723
  id: row.id,
1661
1724
  text: row.text ?? "",
1662
1725
  source: row.source,
1663
1726
  score: 1 - row.distance,
1664
- vectorScore: 1 - row.distance
1727
+ vectorScore: 1 - row.distance,
1728
+ createdAt: row.timestamp ?? void 0
1665
1729
  }));
1666
1730
  } catch (error) {
1667
1731
  log5.error({ err: error }, "Vector search error (messages)");
1668
1732
  return [];
1669
1733
  }
1670
1734
  }
1671
- keywordSearchMessages(query, limit, chatId) {
1735
+ keywordSearchMessages(query, limit, chatId, afterTimestamp) {
1672
1736
  const safeQuery = escapeFts5Query(query);
1673
1737
  if (!safeQuery) return [];
1674
1738
  try {
1675
- const sql = chatId ? `
1676
- SELECT m.id, m.text, m.chat_id as source, rank as score
1677
- FROM tg_messages_fts mf
1678
- JOIN tg_messages m ON m.rowid = mf.rowid
1679
- WHERE tg_messages_fts MATCH ? AND m.chat_id = ?
1680
- ORDER BY rank
1681
- LIMIT ?
1682
- ` : `
1683
- SELECT m.id, m.text, m.chat_id as source, rank as score
1739
+ const conditions = ["tg_messages_fts MATCH ?"];
1740
+ const params = [safeQuery];
1741
+ if (chatId) {
1742
+ conditions.push("m.chat_id = ?");
1743
+ params.push(chatId);
1744
+ }
1745
+ if (afterTimestamp) {
1746
+ conditions.push("m.timestamp >= ?");
1747
+ params.push(afterTimestamp);
1748
+ }
1749
+ params.push(limit);
1750
+ const sql = `
1751
+ SELECT m.id, m.text, m.chat_id as source, rank as score, m.timestamp
1684
1752
  FROM tg_messages_fts mf
1685
1753
  JOIN tg_messages m ON m.rowid = mf.rowid
1686
- WHERE tg_messages_fts MATCH ?
1754
+ WHERE ${conditions.join(" AND ")}
1687
1755
  ORDER BY rank
1688
1756
  LIMIT ?
1689
1757
  `;
1690
- const rows = chatId ? this.db.prepare(sql).all(safeQuery, chatId, limit) : this.db.prepare(sql).all(safeQuery, limit);
1758
+ const rows = this.db.prepare(sql).all(...params);
1691
1759
  return rows.map((row) => ({
1692
1760
  ...row,
1693
1761
  text: row.text ?? "",
1694
- keywordScore: this.bm25ToScore(row.score)
1762
+ keywordScore: this.bm25ToScore(row.score),
1763
+ createdAt: row.timestamp ?? void 0
1695
1764
  }));
1696
1765
  } catch (error) {
1697
1766
  log5.error({ err: error }, "FTS5 search error (messages)");
@@ -1712,7 +1781,16 @@ var HybridSearch = class {
1712
1781
  byId.set(r.id, { ...r, score: keywordWeight * (r.keywordScore ?? 0) });
1713
1782
  }
1714
1783
  }
1715
- return Array.from(byId.values()).filter((r) => r.score >= HYBRID_SEARCH_MIN_SCORE).sort((a, b) => b.score - a.score).slice(0, limit);
1784
+ const now = Math.floor(Date.now() / 1e3);
1785
+ const results = Array.from(byId.values());
1786
+ for (const r of results) {
1787
+ if (r.createdAt) {
1788
+ const ageDays = Math.max(0, (now - r.createdAt) / SECONDS_PER_DAY);
1789
+ const boost = 1 / (1 + ageDays * RECENCY_DECAY_FACTOR);
1790
+ r.score *= 1 - RECENCY_WEIGHT + RECENCY_WEIGHT * boost;
1791
+ }
1792
+ }
1793
+ return results.filter((r) => r.score >= HYBRID_SEARCH_MIN_SCORE).sort((a, b) => b.score - a.score).slice(0, limit);
1716
1794
  }
1717
1795
  /**
1718
1796
  * Convert BM25 rank to normalized score.
@@ -1776,7 +1854,12 @@ var ContextBuilder = class {
1776
1854
  log6.warn({ err: error }, "Knowledge search failed");
1777
1855
  return [];
1778
1856
  }) : Promise.resolve([]);
1779
- const feedPromise = includeFeedHistory ? this.hybridSearch.searchMessages(query, queryEmbedding, { chatId, limit: maxRelevantChunks }).catch((error) => {
1857
+ const { afterTimestamp } = parseTemporalIntent(query);
1858
+ const feedPromise = includeFeedHistory ? this.hybridSearch.searchMessages(query, queryEmbedding, {
1859
+ chatId,
1860
+ limit: maxRelevantChunks,
1861
+ afterTimestamp
1862
+ }).catch((error) => {
1780
1863
  log6.warn({ err: error }, "Feed search failed");
1781
1864
  return [];
1782
1865
  }) : Promise.resolve([]);
@@ -1863,6 +1946,7 @@ export {
1863
1946
  MessageStore,
1864
1947
  ChatStore,
1865
1948
  UserStore,
1949
+ parseTemporalIntent,
1866
1950
  HybridSearch,
1867
1951
  ContextBuilder,
1868
1952
  initializeMemory