teleton 0.8.4 → 0.8.6

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 (84) hide show
  1. package/README.md +40 -17
  2. package/dist/{bootstrap-NNEI3Z5H.js → bootstrap-PFBH6ALD.js} +11 -8
  3. package/dist/bridge-guards-HZTNH7IB.js +9 -0
  4. package/dist/{chunk-NH2CNRKJ.js → chunk-2UUGRY5B.js} +151 -159
  5. package/dist/{chunk-UMUONAD6.js → chunk-4MFN75ZK.js} +5941 -2716
  6. package/dist/{chunk-LC4TV3KL.js → chunk-4MG2AROG.js} +5 -7
  7. package/dist/{chunk-LZQOX6YY.js → chunk-6IFNQWIM.js} +7714 -8748
  8. package/dist/chunk-7KI25UJU.js +215 -0
  9. package/dist/chunk-AX5NBEHX.js +12 -0
  10. package/dist/{chunk-5LOHRZYY.js → chunk-BLUES3FJ.js} +80 -101
  11. package/dist/{chunk-CUE4UZXR.js → chunk-BT2I3ETV.js} +3 -3
  12. package/dist/chunk-CXTZPOTA.js +107 -0
  13. package/dist/{chunk-LVTKJQ7O.js → chunk-D3GT6YIY.js} +59 -7
  14. package/dist/chunk-EKCXKL5M.js +53 -0
  15. package/dist/{chunk-XDZDOKIF.js → chunk-F6S3L3OV.js} +3 -3
  16. package/dist/{chunk-C4NKJT2Z.js → chunk-J4WDJ7XS.js} +1 -1
  17. package/dist/{chunk-G7PCW63M.js → chunk-JYF2MM5I.js} +147 -113
  18. package/dist/{chunk-NVKBBTI6.js → chunk-K3QSIIMZ.js} +9 -6
  19. package/dist/{chunk-EYWNOHMJ.js → chunk-L653KKCR.js} +1 -0
  20. package/dist/chunk-OMQIAWEU.js +273 -0
  21. package/dist/chunk-PCT7GYBP.js +274 -0
  22. package/dist/chunk-QYZBWU2D.js +139 -0
  23. package/dist/{chunk-WTDAICGT.js → chunk-R6W4DJRK.js} +7 -7
  24. package/dist/{chunk-5SEMA47R.js → chunk-RILOEIK6.js} +1 -1
  25. package/dist/{chunk-6OOHHJ4N.js → chunk-TFTNZZDH.js} +20 -20
  26. package/dist/chunk-TTOZCZWE.js +96 -0
  27. package/dist/chunk-UJ54YT2T.js +12 -0
  28. package/dist/{chunk-GHMXWAXI.js → chunk-ULVL2W3D.js} +211 -445
  29. package/dist/{chunk-NQ6FZKCE.js → chunk-V3S3NXBQ.js} +3 -1
  30. package/dist/{chunk-H7MFXJZK.js → chunk-WSL4KIOI.js} +31 -26
  31. package/dist/{chunk-35MX4ZUI.js → chunk-Z5WY7BSB.js} +5 -5
  32. package/dist/{chunk-ALKAAG4O.js → chunk-ZGKE3OTA.js} +112 -49
  33. package/dist/{chunk-JROBTXWY.js → chunk-ZHRDETCX.js} +38 -4
  34. package/dist/cli/index.d.ts +2 -0
  35. package/dist/cli/index.js +272 -159
  36. package/dist/{client-5KD25NOP.js → client-S5UIK6OG.js} +10 -8
  37. package/dist/daily-logs-3WXGYAQF.js +25 -0
  38. package/dist/{get-my-gifts-Y7EN7RK4.js → get-my-gifts-3YSYM3LI.js} +3 -2
  39. package/dist/harden-permissions-PV5SGV5D.js +100 -0
  40. package/dist/index.d.ts +923 -0
  41. package/dist/index.js +29 -20
  42. package/dist/knowledge-RRWUIO3G.js +19 -0
  43. package/dist/{local-IHKJFQJS.js → local-MSZAXWUL.js} +3 -3
  44. package/dist/mcp-loader-OELDFR63.js +15 -0
  45. package/dist/{memory-QMJRM3XJ.js → memory-6U6HGRK2.js} +23 -12
  46. package/dist/memory-hook-T7Y235KY.js +19 -0
  47. package/dist/messages-KV5ADNJB.js +17 -0
  48. package/dist/{migrate-5VBAP52B.js → migrate-AX3HOKOO.js} +10 -7
  49. package/dist/{paths-XA2RJH4S.js → paths-WMVV7ZAJ.js} +1 -1
  50. package/dist/{server-WWGVDFPW.js → server-MFRYOGHR.js} +21 -23
  51. package/dist/{server-AJCOURH7.js → server-SFLCAZFR.js} +221 -27
  52. package/dist/{setup-server-VDY64CWW.js → setup-server-YWAPKZVE.js} +26 -26
  53. package/dist/{store-BY7S6IFN.js → store-PGHQASBC.js} +11 -8
  54. package/dist/{task-dependency-resolver-L6UUMTHK.js → task-dependency-resolver-YQKADDEU.js} +24 -10
  55. package/dist/{task-executor-XBNJLUCS.js → task-executor-LWAWD225.js} +4 -4
  56. package/dist/{tool-adapter-IVX2XQJE.js → tool-adapter-VKLUZSQS.js} +1 -1
  57. package/dist/{tool-index-FTERJSZK.js → tool-index-YEWDF5CK.js} +5 -5
  58. package/dist/{transcript-IM7G25OS.js → transcript-4Y3Z2BJ3.js} +3 -3
  59. package/dist/web/assets/Config-MNxA69ib.js +1 -0
  60. package/dist/web/assets/Conversations-Dk958paA.js +1 -0
  61. package/dist/web/assets/Dashboard-dM18fGOm.js +1 -0
  62. package/dist/web/assets/Hooks-D2griQnI.js +1 -0
  63. package/dist/web/assets/Mcp-CtWNzwsz.js +1 -0
  64. package/dist/web/assets/Memory-CfLwH45G.js +1 -0
  65. package/dist/web/assets/Plugins-3hoJprFo.js +1 -0
  66. package/dist/web/assets/SearchInput-CpcETdpE.js +1 -0
  67. package/dist/web/assets/Soul-BSxE73aK.js +1 -0
  68. package/dist/web/assets/Tasks-DkCkfu3A.js +1 -0
  69. package/dist/web/assets/TelegramSettingsPanel-BRzc5G6e.js +1 -0
  70. package/dist/web/assets/Tools-Du8B8Mb4.js +1 -0
  71. package/dist/web/assets/Wallet-BLILP2Gn.js +1 -0
  72. package/dist/web/assets/Workspace-qklcXpXV.js +1 -0
  73. package/dist/web/assets/index-BwEPTTKp.js +90 -0
  74. package/dist/web/assets/index-noejUsK7.css +1 -0
  75. package/dist/web/assets/{index.es-DitvF-9H.js → index.es-DdpKlnGb.js} +1 -1
  76. package/dist/web/assets/useToolManager-tdxkKn3H.js +1 -0
  77. package/dist/web/assets/utils-CnsbSMo4.js +1 -0
  78. package/dist/web/index.html +2 -2
  79. package/package.json +7 -12
  80. package/src/templates/HEARTBEAT.md +5 -0
  81. package/dist/memory-hook-VUNWZ3NY.js +0 -19
  82. package/dist/web/assets/index-BfYCdwLI.js +0 -80
  83. package/dist/web/assets/index-DmlyQVhR.css +0 -1
  84. package/dist/{chunk-WFTC3JJW.js → chunk-3NO7QU7W.js} +1 -1
@@ -105,7 +105,9 @@ var rootLogger = pino(
105
105
  "*.password",
106
106
  "*.secret",
107
107
  "*.token",
108
- "*.mnemonic"
108
+ "*.mnemonic",
109
+ "bot_token",
110
+ "*.bot_token"
109
111
  ],
110
112
  censor: "[REDACTED]"
111
113
  }
@@ -1,9 +1,12 @@
1
+ import {
2
+ getClient
3
+ } from "./chunk-EKCXKL5M.js";
1
4
  import {
2
5
  getErrorMessage
3
6
  } from "./chunk-3UFPFWYP.js";
4
7
  import {
5
8
  createLogger
6
- } from "./chunk-NQ6FZKCE.js";
9
+ } from "./chunk-V3S3NXBQ.js";
7
10
 
8
11
  // src/agent/tools/telegram/gifts/get-my-gifts.ts
9
12
  import { Type } from "@sinclair/typebox";
@@ -12,12 +15,12 @@ var log = createLogger("Tools");
12
15
  var giftCatalogCache = null;
13
16
  var CATALOG_CACHE_TTL_MS = 5 * 60 * 1e3;
14
17
  function extractEmoji(sticker) {
15
- if (!sticker?.attributes) return null;
18
+ if (!("attributes" in sticker)) return null;
16
19
  const attr = sticker.attributes.find(
17
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- GramJS API response is untyped
18
20
  (a) => a.className === "DocumentAttributeSticker" || a.className === "DocumentAttributeCustomEmoji"
19
21
  );
20
- return attr?.alt || null;
22
+ if (!attr) return null;
23
+ return "alt" in attr ? attr.alt || null : null;
21
24
  }
22
25
  var telegramGetMyGiftsTool = {
23
26
  name: "telegram_get_my_gifts",
@@ -58,6 +61,15 @@ var telegramGetMyGiftsTool = {
58
61
  }),
59
62
  category: "data-bearing"
60
63
  };
64
+ function extractAttrSummary(attr) {
65
+ if (!attr || !("name" in attr) || !("rarity" in attr)) return null;
66
+ const rarity = attr.rarity;
67
+ const permille = "permille" in rarity ? rarity.permille : null;
68
+ return {
69
+ name: attr.name,
70
+ rarityPercent: permille ? (Number(permille) / 10).toFixed(1) + "%" : null
71
+ };
72
+ }
61
73
  var telegramGetMyGiftsExecutor = async (params, context) => {
62
74
  try {
63
75
  const {
@@ -68,7 +80,7 @@ var telegramGetMyGiftsExecutor = async (params, context) => {
68
80
  excludeSaved,
69
81
  sortByValue = false
70
82
  } = params;
71
- const gramJsClient = context.bridge.getClient().getClient();
83
+ const gramJsClient = getClient(context.bridge);
72
84
  const targetUserId = viewSender ? context.senderId.toString() : userId;
73
85
  const peer = targetUserId ? await gramJsClient.getEntity(targetUserId) : new Api.InputPeerSelf();
74
86
  let catalogMap;
@@ -76,12 +88,11 @@ var telegramGetMyGiftsExecutor = async (params, context) => {
76
88
  catalogMap = giftCatalogCache.map;
77
89
  } else {
78
90
  const prevHash = giftCatalogCache?.hash ?? 0;
79
- const catalog = await gramJsClient.invoke(
80
- new Api.payments.GetStarGifts({ hash: prevHash })
81
- );
82
- if (catalog.gifts && catalog.gifts.length > 0) {
91
+ const catalog = await gramJsClient.invoke(new Api.payments.GetStarGifts({ hash: prevHash }));
92
+ if (catalog.className === "payments.StarGifts" && catalog.gifts.length > 0) {
83
93
  catalogMap = /* @__PURE__ */ new Map();
84
94
  for (const catalogGift of catalog.gifts) {
95
+ if (catalogGift.className !== "StarGift") continue;
85
96
  const id = catalogGift.id?.toString();
86
97
  if (id) {
87
98
  catalogMap.set(id, {
@@ -102,7 +113,7 @@ var telegramGetMyGiftsExecutor = async (params, context) => {
102
113
  catalogMap = giftCatalogCache?.map ?? /* @__PURE__ */ new Map();
103
114
  giftCatalogCache = {
104
115
  map: catalogMap,
105
- hash: catalog.hash ?? giftCatalogCache?.hash ?? 0,
116
+ hash: catalog.className === "payments.StarGifts" ? catalog.hash ?? 0 : giftCatalogCache?.hash ?? 0,
106
117
  expiresAt: Date.now() + CATALOG_CACHE_TTL_MS
107
118
  };
108
119
  }
@@ -119,19 +130,15 @@ var telegramGetMyGiftsExecutor = async (params, context) => {
119
130
  );
120
131
  const gifts = (result.gifts || []).map((savedGift) => {
121
132
  const gift = savedGift.gift;
122
- const isCollectible = gift?.className === "StarGiftUnique";
133
+ const isCollectible = gift.className === "StarGiftUnique";
123
134
  const lookupId = isCollectible ? gift.giftId?.toString() : gift.id?.toString();
124
135
  const catalogInfo = catalogMap.get(lookupId);
125
136
  const isLimited = isCollectible || catalogInfo?.limited === true;
126
- const extractAttrSummary = (attr) => attr ? {
127
- name: attr.name,
128
- rarityPercent: attr.rarityPermille ? (attr.rarityPermille / 10).toFixed(1) + "%" : null
129
- } : null;
130
137
  const compactGift = {
131
138
  date: savedGift.date,
132
139
  isLimited,
133
140
  isCollectible,
134
- stars: gift?.stars?.toString(),
141
+ stars: isCollectible ? void 0 : gift.stars?.toString(),
135
142
  emoji: catalogInfo?.emoji || null,
136
143
  msgId: savedGift.msgId,
137
144
  savedId: savedGift.savedId?.toString(),
@@ -143,30 +150,29 @@ var telegramGetMyGiftsExecutor = async (params, context) => {
143
150
  compactGift.num = gift.num;
144
151
  compactGift.slug = gift.slug;
145
152
  compactGift.nftLink = `t.me/nft/${gift.slug}`;
146
- const modelAttr = gift.attributes?.find(
147
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- GramJS API response is untyped
153
+ const modelAttr = gift.attributes.find(
148
154
  (a) => a.className === "StarGiftAttributeModel"
149
155
  );
150
- const patternAttr = gift.attributes?.find(
151
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- GramJS API response is untyped
156
+ const patternAttr = gift.attributes.find(
152
157
  (a) => a.className === "StarGiftAttributePattern"
153
158
  );
154
- const backdropAttr = gift.attributes?.find(
155
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- GramJS API response is untyped
159
+ const backdropAttr = gift.attributes.find(
156
160
  (a) => a.className === "StarGiftAttributeBackdrop"
157
161
  );
158
162
  compactGift.model = extractAttrSummary(modelAttr);
159
163
  compactGift.pattern = extractAttrSummary(patternAttr);
160
164
  compactGift.backdrop = extractAttrSummary(backdropAttr);
161
165
  } else {
166
+ const regularGift = gift;
162
167
  compactGift.canUpgrade = savedGift.canUpgrade || false;
163
168
  if (savedGift.canUpgrade) {
164
- compactGift.upgradeStars = gift?.upgradeStars?.toString();
169
+ compactGift.upgradeStars = regularGift.upgradeStars?.toString();
165
170
  }
166
171
  }
167
172
  if (isLimited && !isCollectible) {
168
- compactGift.availabilityRemains = catalogInfo?.availabilityRemains || gift?.availabilityRemains;
169
- compactGift.availabilityTotal = catalogInfo?.availabilityTotal || gift?.availabilityTotal;
173
+ const regularGift = gift;
174
+ compactGift.availabilityRemains = catalogInfo?.availabilityRemains || regularGift.availabilityRemains;
175
+ compactGift.availabilityTotal = catalogInfo?.availabilityTotal || regularGift.availabilityTotal;
170
176
  }
171
177
  return compactGift;
172
178
  });
@@ -187,7 +193,6 @@ var telegramGetMyGiftsExecutor = async (params, context) => {
187
193
  limited: limited.length,
188
194
  unlimited: unlimited.length,
189
195
  collectibles: collectibles.length,
190
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- GramJS API response is untyped
191
196
  canUpgrade: gifts.filter((g) => g.canUpgrade).length
192
197
  },
193
198
  totalCount: result.count
@@ -7,16 +7,16 @@ import {
7
7
  EMBEDDING_CACHE_MAX_ENTRIES,
8
8
  EMBEDDING_CACHE_TTL_DAYS,
9
9
  VOYAGE_BATCH_SIZE
10
- } from "./chunk-C4NKJT2Z.js";
10
+ } from "./chunk-J4WDJ7XS.js";
11
11
  import {
12
12
  fetchWithTimeout
13
13
  } from "./chunk-XQUHC3JZ.js";
14
14
  import {
15
15
  LocalEmbeddingProvider
16
- } from "./chunk-CUE4UZXR.js";
16
+ } from "./chunk-BT2I3ETV.js";
17
17
  import {
18
18
  createLogger
19
- } from "./chunk-NQ6FZKCE.js";
19
+ } from "./chunk-V3S3NXBQ.js";
20
20
 
21
21
  // src/memory/embeddings/provider.ts
22
22
  var NoopEmbeddingProvider = class {
@@ -229,8 +229,8 @@ var CachedEmbeddingProvider = class _CachedEmbeddingProvider {
229
229
  `Embedding cache eviction: removed ${toDelete} entries (${count} total)`
230
230
  );
231
231
  }
232
- } catch (err) {
233
- _CachedEmbeddingProvider.log.warn({ err }, "Embedding cache eviction error");
232
+ } catch (error) {
233
+ _CachedEmbeddingProvider.log.warn({ err: error }, "Embedding cache eviction error");
234
234
  }
235
235
  }
236
236
  };
@@ -13,16 +13,17 @@ import {
13
13
  SESSION_SLUG_MAX_TOKENS,
14
14
  SESSION_SLUG_RECENT_MESSAGES,
15
15
  TOKEN_ESTIMATE_SAFETY_MARGIN
16
- } from "./chunk-C4NKJT2Z.js";
16
+ } from "./chunk-J4WDJ7XS.js";
17
17
  import {
18
18
  getUtilityModel
19
- } from "./chunk-LVTKJQ7O.js";
19
+ } from "./chunk-D3GT6YIY.js";
20
20
  import {
21
21
  createLogger
22
- } from "./chunk-NQ6FZKCE.js";
22
+ } from "./chunk-V3S3NXBQ.js";
23
23
 
24
24
  // src/session/memory-hook.ts
25
- import { writeFile, mkdir, readdir, readFile, unlink } from "fs/promises";
25
+ import { writeFile, mkdir, readdir, readFile } from "fs/promises";
26
+ import { mkdirSync, renameSync } from "fs";
26
27
  import { join } from "path";
27
28
  import { complete as complete2 } from "@mariozechner/pi-ai";
28
29
 
@@ -259,9 +260,7 @@ async function summarizeWithFallback(params) {
259
260
  utilityModel: params.utilityModel
260
261
  });
261
262
  } catch (fullError) {
262
- log.warn(
263
- `Full summarization failed: ${fullError instanceof Error ? fullError.message : String(fullError)}`
264
- );
263
+ log.warn(`Full summarization failed: ${getErrorMessage(fullError)}`);
265
264
  }
266
265
  const smallMessages = [];
267
266
  const oversizedNotes = [];
@@ -299,9 +298,7 @@ ${oversizedNotes.join("\n")}` : "";
299
298
  chunksProcessed: result.chunksProcessed
300
299
  };
301
300
  } catch (partialError) {
302
- log.warn(
303
- `Partial summarization also failed: ${partialError instanceof Error ? partialError.message : String(partialError)}`
304
- );
301
+ log.warn(`Partial summarization also failed: ${getErrorMessage(partialError)}`);
305
302
  }
306
303
  }
307
304
  const note = `Context contained ${params.messages.length} messages (${oversizedNotes.length} were oversized). AI summarization unavailable due to size constraints. Recent conversation history was preserved.`;
@@ -352,7 +349,7 @@ Slug:`,
352
349
  }
353
350
  async function saveSessionMemory(params) {
354
351
  try {
355
- const { TELETON_ROOT } = await import("./paths-XA2RJH4S.js");
352
+ const { TELETON_ROOT } = await import("./paths-WMVV7ZAJ.js");
356
353
  const memoryDir = join(TELETON_ROOT, "memory");
357
354
  await mkdir(memoryDir, { recursive: true });
358
355
  const now = /* @__PURE__ */ new Date();
@@ -405,6 +402,11 @@ This session was compacted and migrated to a new session ID. The summary above p
405
402
  *Generated automatically by Teleton-AI session memory hook*
406
403
  `;
407
404
  await writeFile(filepath, content, "utf-8");
405
+ const { writeSessionEndSummary } = await import("./daily-logs-3WXGYAQF.js");
406
+ writeSessionEndSummary(summary, "compaction");
407
+ const { getKnowledgeIndexer } = await import("./knowledge-RRWUIO3G.js");
408
+ getKnowledgeIndexer()?.indexFile(filepath).catch(() => {
409
+ });
408
410
  const relPath = filepath.replace(TELETON_ROOT, "~/.teleton");
409
411
  log2.info(`Session memory saved: ${relPath}`);
410
412
  } catch (error) {
@@ -412,53 +414,111 @@ This session was compacted and migrated to a new session ID. The summary above p
412
414
  }
413
415
  }
414
416
  var CONSOLIDATION_THRESHOLD = 20;
415
- var CONSOLIDATION_BATCH = 10;
417
+ var CONSOLIDATION_AGE_DAYS = 7;
418
+ var CONSOLIDATION_FALLBACK_BATCH = 10;
419
+ var CONSOLIDATION_MAX_TOKENS = 4e3;
420
+ var CONSOLIDATION_MIN_CLUSTER_SIZE = 2;
416
421
  async function consolidateOldMemoryFiles(params) {
417
422
  try {
418
- const { TELETON_ROOT } = await import("./paths-XA2RJH4S.js");
423
+ const { TELETON_ROOT } = await import("./paths-WMVV7ZAJ.js");
419
424
  const memoryDir = join(TELETON_ROOT, "memory");
425
+ const archiveDir = join(memoryDir, "archived");
420
426
  let entries;
421
427
  try {
422
428
  entries = await readdir(memoryDir);
423
429
  } catch {
424
430
  return { consolidated: 0 };
425
431
  }
426
- const sessionFiles = entries.filter((f) => /^\d{4}-\d{2}-\d{2}-.+\.md$/.test(f) && !f.startsWith("consolidated-")).sort();
432
+ const cutoff = /* @__PURE__ */ new Date();
433
+ cutoff.setDate(cutoff.getDate() - CONSOLIDATION_AGE_DAYS);
434
+ const cutoffStr = cutoff.toISOString().split("T")[0];
435
+ const sessionFiles = entries.filter(
436
+ (f) => /^\d{4}-\d{2}-\d{2}-.+\.md$/.test(f) && !f.startsWith("consolidated-") && f.slice(0, 10) < cutoffStr
437
+ ).sort();
427
438
  if (sessionFiles.length < CONSOLIDATION_THRESHOLD) {
428
439
  return { consolidated: 0 };
429
440
  }
430
- const batch = sessionFiles.slice(0, CONSOLIDATION_BATCH);
431
- log2.info(`Consolidating ${batch.length} old session memory files...`);
432
- const contents = [];
433
- for (const file of batch) {
434
- const text = await readFile(join(memoryDir, file), "utf-8");
435
- contents.push(`--- ${file} ---
436
- ${text}`);
441
+ const fileKeywords = [];
442
+ for (const file of sessionFiles) {
443
+ const slug = file.slice(11).replace(/\.md$/, "");
444
+ const slugWords = slug.split("-").filter((w) => w.length > 3);
445
+ let headingWords = [];
446
+ try {
447
+ const text = await readFile(join(memoryDir, file), "utf-8");
448
+ const firstHeading = text.split("\n").find((l) => l.startsWith("#")) ?? "";
449
+ headingWords = firstHeading.replace(/^#+\s*/, "").toLowerCase().split(/\W+/).filter((w) => w.length > 3);
450
+ } catch {
451
+ }
452
+ fileKeywords.push({ file, keywords: /* @__PURE__ */ new Set([...slugWords, ...headingWords]) });
437
453
  }
438
- const combined = contents.join("\n\n");
439
- let summary;
440
- try {
441
- const result = await summarizeWithFallback({
442
- messages: [{ role: "user", content: combined, timestamp: Date.now() }],
443
- apiKey: params.apiKey,
444
- contextWindow: DEFAULT_CONTEXT_WINDOW,
445
- maxSummaryTokens: DEFAULT_MAX_SUMMARY_TOKENS,
446
- customInstructions: "Consolidate these session memories into a single comprehensive summary. Preserve key facts, decisions, patterns, and important context. Remove redundancy. Organize by topic.",
447
- provider: params.provider,
448
- utilityModel: params.utilityModel
449
- });
450
- summary = result.summary;
451
- } catch (error) {
452
- log2.warn({ err: error }, "Consolidation summary failed, skipping");
453
- return { consolidated: 0 };
454
+ const assigned = /* @__PURE__ */ new Set();
455
+ const clusters = [];
456
+ for (let i = 0; i < fileKeywords.length; i++) {
457
+ if (assigned.has(fileKeywords[i].file)) continue;
458
+ const cluster = [fileKeywords[i].file];
459
+ assigned.add(fileKeywords[i].file);
460
+ for (let j = i + 1; j < fileKeywords.length; j++) {
461
+ if (assigned.has(fileKeywords[j].file)) continue;
462
+ const hasOverlap = [...fileKeywords[i].keywords].some(
463
+ (k) => fileKeywords[j].keywords.has(k)
464
+ );
465
+ if (hasOverlap) {
466
+ cluster.push(fileKeywords[j].file);
467
+ assigned.add(fileKeywords[j].file);
468
+ }
469
+ }
470
+ if (cluster.length >= CONSOLIDATION_MIN_CLUSTER_SIZE) {
471
+ clusters.push(cluster);
472
+ }
454
473
  }
455
- const dateOf = (f) => f.slice(0, 10);
456
- const dateRange = `${dateOf(batch[0])}_to_${dateOf(batch[batch.length - 1])}`;
457
- const outFile = `consolidated-${dateRange}.md`;
458
- const outContent = `# Consolidated Session Memories
474
+ if (clusters.length === 0) {
475
+ log2.info("No thematic clusters found, falling back to chronological grouping");
476
+ clusters.push(sessionFiles.slice(0, CONSOLIDATION_FALLBACK_BATCH));
477
+ }
478
+ mkdirSync(archiveDir, { recursive: true });
479
+ let totalConsolidated = 0;
480
+ for (const cluster of clusters) {
481
+ log2.info(
482
+ `Consolidating cluster of ${cluster.length} files: ${cluster.slice(0, 3).join(", ")}${cluster.length > 3 ? "\u2026" : ""}`
483
+ );
484
+ const contents = [];
485
+ for (const file of cluster) {
486
+ const text = await readFile(join(memoryDir, file), "utf-8");
487
+ contents.push(`--- ${file} ---
488
+ ${text}`);
489
+ }
490
+ const combined = contents.join("\n\n");
491
+ const sourceList = cluster.map((f) => `- ${f}`).join("\n");
492
+ let summary;
493
+ try {
494
+ const result = await summarizeWithFallback({
495
+ messages: [{ role: "user", content: combined, timestamp: Date.now() }],
496
+ apiKey: params.apiKey,
497
+ contextWindow: DEFAULT_CONTEXT_WINDOW,
498
+ maxSummaryTokens: CONSOLIDATION_MAX_TOKENS,
499
+ customInstructions: `Consolidate these session memories into a single comprehensive summary.
500
+ Source files:
501
+ ${sourceList}
502
+
503
+ Preserve key facts, decisions, patterns, and important context. Remove redundancy. Organize by topic. You may reference source file names when relevant.`,
504
+ provider: params.provider,
505
+ utilityModel: params.utilityModel
506
+ });
507
+ summary = result.summary;
508
+ } catch (error) {
509
+ log2.warn({ err: error }, "Consolidation summary failed for cluster, skipping");
510
+ continue;
511
+ }
512
+ const dateOf = (f) => f.slice(0, 10);
513
+ const dateRange = `${dateOf(cluster[0])}_to_${dateOf(cluster[cluster.length - 1])}`;
514
+ const outFile = `consolidated-${dateRange}.md`;
515
+ const outContent = `# Consolidated Session Memories
459
516
 
460
- ## Period
461
- ${batch[0]} \u2192 ${batch[batch.length - 1]}
517
+ ## Metadata
518
+
519
+ - **Period**: ${cluster[0]} \u2192 ${cluster[cluster.length - 1]}
520
+ - **Source Files** (${cluster.length}):
521
+ ${sourceList}
462
522
 
463
523
  ## Summary
464
524
 
@@ -466,14 +526,16 @@ ${summary}
466
526
 
467
527
  ---
468
528
 
469
- *Consolidated from ${batch.length} session files by Teleton memory consolidation*
529
+ *Consolidated from ${cluster.length} session files. Originals archived in memory/archived/.*
470
530
  `;
471
- await writeFile(join(memoryDir, outFile), outContent, "utf-8");
472
- for (const file of batch) {
473
- await unlink(join(memoryDir, file));
531
+ await writeFile(join(memoryDir, outFile), outContent, "utf-8");
532
+ for (const file of cluster) {
533
+ renameSync(join(memoryDir, file), join(archiveDir, file));
534
+ }
535
+ totalConsolidated += cluster.length;
536
+ log2.info(`Consolidated ${cluster.length} files \u2192 ${outFile}`);
474
537
  }
475
- log2.info(`Consolidated ${batch.length} files \u2192 ${outFile}`);
476
- return { consolidated: batch.length };
538
+ return { consolidated: totalConsolidated };
477
539
  } catch (error) {
478
540
  log2.error({ err: error }, "Memory consolidation failed");
479
541
  return { consolidated: 0 };
@@ -481,6 +543,7 @@ ${summary}
481
543
  }
482
544
 
483
545
  export {
546
+ summarizeViaClaude,
484
547
  summarizeWithFallback,
485
548
  saveSessionMemory,
486
549
  consolidateOldMemoryFiles
@@ -1,23 +1,23 @@
1
1
  import {
2
2
  ConfigSchema,
3
3
  expandPath
4
- } from "./chunk-NH2CNRKJ.js";
4
+ } from "./chunk-2UUGRY5B.js";
5
5
  import {
6
6
  COINGECKO_API_URL,
7
7
  tonapiFetch
8
8
  } from "./chunk-VFA7QMCZ.js";
9
9
  import {
10
10
  getSupportedProviders
11
- } from "./chunk-6OOHHJ4N.js";
11
+ } from "./chunk-TFTNZZDH.js";
12
12
  import {
13
13
  fetchWithTimeout
14
14
  } from "./chunk-XQUHC3JZ.js";
15
15
  import {
16
16
  TELETON_ROOT
17
- } from "./chunk-EYWNOHMJ.js";
17
+ } from "./chunk-L653KKCR.js";
18
18
  import {
19
19
  createLogger
20
- } from "./chunk-NQ6FZKCE.js";
20
+ } from "./chunk-V3S3NXBQ.js";
21
21
 
22
22
  // src/ton/endpoint.ts
23
23
  var ENDPOINT_CACHE_TTL_MS = 6e4;
@@ -807,6 +807,40 @@ var CONFIGURABLE_KEYS = {
807
807
  mask: identity,
808
808
  parse: identity
809
809
  },
810
+ // ─── Heartbeat ─────────────────────────────────────────────────────
811
+ "heartbeat.enabled": {
812
+ type: "boolean",
813
+ category: "Agent",
814
+ label: "Heartbeat Enabled",
815
+ description: "Enable periodic heartbeat timer",
816
+ sensitive: false,
817
+ hotReload: "instant",
818
+ validate: enumValidator(["true", "false"]),
819
+ mask: identity,
820
+ parse: (v) => v === "true"
821
+ },
822
+ "heartbeat.interval_ms": {
823
+ type: "number",
824
+ category: "Agent",
825
+ label: "Heartbeat Interval (ms)",
826
+ description: "Heartbeat interval in milliseconds (min 60000)",
827
+ sensitive: false,
828
+ hotReload: "restart",
829
+ validate: numberInRange(6e4, 864e5),
830
+ mask: identity,
831
+ parse: (v) => Number(v)
832
+ },
833
+ "heartbeat.self_configurable": {
834
+ type: "boolean",
835
+ category: "Agent",
836
+ label: "Heartbeat Self-Configurable",
837
+ description: "Allow agent to modify heartbeat config at runtime",
838
+ sensitive: false,
839
+ hotReload: "instant",
840
+ validate: enumValidator(["true", "false"]),
841
+ mask: identity,
842
+ parse: (v) => v === "true"
843
+ },
810
844
  // ─── Developer ─────────────────────────────────────────────────────
811
845
  "dev.hot_reload": {
812
846
  type: "boolean",
@@ -0,0 +1,2 @@
1
+
2
+ export { }