omnius 1.0.137 → 1.0.139

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/index.js CHANGED
@@ -623811,214 +623811,29 @@ ${lines.join("\n")}`);
623811
623811
  const cardCount = (this.chatMemoryCards.get(sessionKey) ?? []).length;
623812
623812
  const memory = this.chatAssociativeMemory.get(sessionKey);
623813
623813
  const factCount = memory?.facts.length ?? 0;
623814
- const relationshipCount = memory?.relationships.length ?? 0;
623815
623814
  const userMemoryCount = memory ? Object.keys(memory.users).length : 0;
623816
623815
  const historyCount = (this.chatHistory.get(sessionKey) ?? []).length;
623817
- let sqliteCount = 0;
623818
- let episodeCount2 = 0;
623819
- try {
623820
- const db = this.telegramDb();
623821
- if (db) {
623822
- const row = db.prepare("SELECT COUNT(*) AS n FROM telegram_messages WHERE session_key = ?").get(sessionKey);
623823
- sqliteCount = Number(row?.n) || 0;
623824
- }
623825
- } catch {
623826
- }
623827
- if (this.repoRoot) {
623828
- try {
623829
- const paths = omniusMemoryDbPaths(this.repoRoot);
623830
- if (existsSync117(paths.episodes)) {
623831
- const graph = new TemporalGraph(paths.knowledge);
623832
- const store2 = new EpisodeStore(paths.episodes, graph);
623833
- try {
623834
- const sample = store2.search({ sessionId: sessionKey, limit: 1 }) ?? [];
623835
- if (sample.length > 0) {
623836
- const dbAny = store2.db;
623837
- if (dbAny && typeof dbAny.prepare === "function") {
623838
- const row = dbAny.prepare("SELECT COUNT(*) AS n FROM episodes WHERE session_id = ?").get(sessionKey);
623839
- episodeCount2 = Number(row?.n) || 0;
623840
- } else {
623841
- episodeCount2 = 1;
623842
- }
623843
- }
623844
- } finally {
623845
- try {
623846
- store2.close();
623847
- } catch {
623848
- }
623849
- try {
623850
- graph.close();
623851
- } catch {
623852
- }
623853
- }
623854
- }
623855
- } catch {
623856
- }
623857
- }
623858
623816
  const chatId = msg.chatId;
623859
- const topicFiles = [];
623817
+ let topicCount = 0;
623860
623818
  if (this.repoRoot && chatId !== void 0) {
623861
623819
  try {
623862
623820
  const memDir = resolve46(this.repoRoot, ".omnius", "memory");
623863
623821
  if (existsSync117(memDir)) {
623864
623822
  const prefix = this.telegramScopedMemoryPrefix(chatId);
623865
623823
  for (const file of readdirSync41(memDir)) {
623866
- if (!file.endsWith(".json") || !file.startsWith(prefix)) continue;
623867
- const topic = file.slice(prefix.length, -".json".length);
623868
- if (topic) topicFiles.push(topic);
623869
- }
623870
- }
623871
- } catch {
623872
- }
623873
- }
623874
- const anyMemory = cardCount + factCount + relationshipCount + userMemoryCount + sqliteCount + episodeCount2 + topicFiles.length > 0;
623875
- if (!anyMemory && historyCount === 0) return "";
623876
- const lines = [
623877
- "### Scoped Memory Substrate (this chat - always present)",
623878
- "Persistent memory is available for this chat. The current turn's lexical scorers may",
623879
- "have surfaced 0 matches above - that does not mean the substrate is empty. Counts:",
623880
- `- Memory cards: ${cardCount}`,
623881
- `- Associative facts: ${factCount}`,
623882
- `- Associative relationships: ${relationshipCount}`,
623883
- `- Per-user memories: ${userMemoryCount}`,
623884
- `- Rolling history entries retained: ${historyCount}`,
623885
- `- Addressable conversation history rows: ${Math.max(historyCount, sqliteCount)}`,
623886
- `- SQLite mirror rows: ${sqliteCount}`,
623887
- `- Episodes (durable, day+ scope): ${episodeCount2}`
623888
- ];
623889
- if (topicFiles.length > 0) {
623890
- lines.push("");
623891
- lines.push("Per-topic memory files (call memory_read with one of these `topic` values):");
623892
- for (const topic of topicFiles.slice(0, 80)) {
623893
- lines.push(` - ${topic}`);
623894
- }
623895
- }
623896
- const anchors = this.telegramHistoryAnchorsForSession(sessionKey, 3);
623897
- const fmtHistoryAnchor = (entry) => {
623898
- const when = entry.ts ? new Date(entry.ts).toISOString() : "(unknown ts)";
623899
- const speaker = telegramHistorySpeaker(entry);
623900
- const kind = entry.role === "assistant" || entry.isBot ? "bot" : "human";
623901
- const mode = entry.mode ? `/${entry.mode}` : "";
623902
- const messageId = entry.messageId ? ` msg:${entry.messageId}` : "";
623903
- return `${when} ${speaker} [${kind}]${mode}${messageId}: ${telegramContextJsonString(String(entry.text || ""), 320)}`;
623904
- };
623905
- const sameHistoryAnchor = (a2, b) => {
623906
- if (!a2 || !b) return false;
623907
- if (a2.messageId !== void 0 && b.messageId !== void 0) return a2.messageId === b.messageId && a2.role === b.role;
623908
- return a2.ts === b.ts && a2.role === b.role && a2.text === b.text;
623909
- };
623910
- if (anchors.earliest.length > 0 || anchors.latest) {
623911
- lines.push("");
623912
- lines.push("Chronological anchors - Telegram conversation history (SQLite mirror preferred; ground truth for 'oldest/newest memory' questions):");
623913
- if (anchors.earliest[0]) lines.push(` Earliest turn: ${fmtHistoryAnchor(anchors.earliest[0])}`);
623914
- if (anchors.latest && !sameHistoryAnchor(anchors.earliest[0], anchors.latest)) {
623915
- lines.push(` Latest turn: ${fmtHistoryAnchor(anchors.latest)}`);
623916
- }
623917
- if (anchors.earliest[1]) {
623918
- lines.push(` 2nd earliest: ${fmtHistoryAnchor(anchors.earliest[1])}`);
623919
- }
623920
- if (anchors.earliest[2]) {
623921
- lines.push(` 3rd earliest: ${fmtHistoryAnchor(anchors.earliest[2])}`);
623922
- }
623923
- }
623924
- const activityStats = this.telegramParticipantActivityStats(sessionKey, { limit: 8 });
623925
- if (activityStats.length > 0) {
623926
- lines.push("");
623927
- lines.push("Activity anchors - participant message counts from the durable mirror/merged history:");
623928
- for (const stat7 of activityStats) {
623929
- const first2 = stat7.firstTs ? new Date(stat7.firstTs).toISOString() : "?";
623930
- const last2 = stat7.lastTs ? new Date(stat7.lastTs).toISOString() : "?";
623931
- lines.push(` - ${stat7.speaker}: ${stat7.count} message${stat7.count === 1 ? "" : "s"} (first:${first2}, last:${last2})`);
623932
- }
623933
- }
623934
- if (this.repoRoot) {
623935
- try {
623936
- const paths = omniusMemoryDbPaths(this.repoRoot);
623937
- if (existsSync117(paths.episodes)) {
623938
- const graph = new TemporalGraph(paths.knowledge);
623939
- const store2 = new EpisodeStore(paths.episodes, graph);
623940
- try {
623941
- const dbAny = store2.db;
623942
- if (dbAny && typeof dbAny.prepare === "function") {
623943
- const earliest = dbAny.prepare(
623944
- "SELECT timestamp, modality, tool_name, content, gist FROM episodes WHERE session_id = ? ORDER BY timestamp ASC LIMIT 1"
623945
- ).get(sessionKey);
623946
- const latest = dbAny.prepare(
623947
- "SELECT timestamp, modality, tool_name, content, gist FROM episodes WHERE session_id = ? ORDER BY timestamp DESC LIMIT 1"
623948
- ).get(sessionKey);
623949
- if (earliest || latest) {
623950
- lines.push("");
623951
- lines.push("Chronological anchors - episodes.db (durable, may reach further back than rolling history):");
623952
- const fmtEp = (row) => {
623953
- const when = row.timestamp ? new Date(row.timestamp).toISOString() : "(unknown ts)";
623954
- const tag = `[${row.modality || "?"}${row.tool_name ? ":" + row.tool_name : ""}]`;
623955
- const text = (row.gist || row.content || "").split("\n").filter((ln) => !/^(Telegram|session:|chat:|message_id:|thread_id:|speaker:|mode:)/i.test(ln.trim())).join(" ").replace(/\s+/g, " ").trim();
623956
- return `${when} ${tag} ${telegramContextJsonString(text, 320)}`;
623957
- };
623958
- if (earliest) lines.push(` Earliest episode: ${fmtEp(earliest)}`);
623959
- if (latest && (!earliest || earliest.timestamp !== latest.timestamp)) lines.push(` Latest episode: ${fmtEp(latest)}`);
623960
- }
623961
- }
623962
- } finally {
623963
- try {
623964
- store2.close();
623965
- } catch {
623966
- }
623967
- try {
623968
- graph.close();
623969
- } catch {
623970
- }
623971
- }
623972
- }
623973
- } catch {
623974
- }
623975
- }
623976
- if (this.repoRoot && chatId !== void 0 && topicFiles.length > 0) {
623977
- try {
623978
- const memDir = resolve46(this.repoRoot, ".omnius", "memory");
623979
- const prefix = this.telegramScopedMemoryPrefix(chatId);
623980
- let earliestEntry = null;
623981
- let latestEntry = null;
623982
- for (const topic of topicFiles) {
623983
- const file = join131(memDir, `${prefix}${topic}.json`);
623984
- if (!existsSync117(file)) continue;
623985
- let parsed;
623986
- try {
623987
- parsed = JSON.parse(readFileSync96(file, "utf8"));
623988
- } catch {
623989
- continue;
623990
- }
623991
- for (const [key, entry] of Object.entries(parsed)) {
623992
- if (!entry || typeof entry !== "object") continue;
623993
- const rawTs = entry.timestamp;
623994
- const ts = typeof rawTs === "string" ? Date.parse(rawTs) : typeof rawTs === "number" ? rawTs : NaN;
623995
- if (!Number.isFinite(ts)) continue;
623996
- const value2 = String(entry.value ?? "");
623997
- if (!earliestEntry || ts < earliestEntry.ts) earliestEntry = { topic, key, value: value2, ts };
623998
- if (!latestEntry || ts > latestEntry.ts) latestEntry = { topic, key, value: value2, ts };
623824
+ if (file.endsWith(".json") && file.startsWith(prefix)) topicCount++;
623999
623825
  }
624000
623826
  }
624001
- if (earliestEntry || latestEntry) {
624002
- lines.push("");
624003
- lines.push("Chronological anchors - memory_write entries (most-trusted, agent-asserted):");
624004
- const fmtMem = (e2) => {
624005
- const when = new Date(e2.ts).toISOString();
624006
- return `${when} topic="${e2.topic}" key="${e2.key}" → ${telegramContextJsonString(e2.value, 320)}`;
624007
- };
624008
- if (earliestEntry) lines.push(` Earliest memory_write: ${fmtMem(earliestEntry)}`);
624009
- if (latestEntry && (!earliestEntry || earliestEntry.ts !== latestEntry.ts)) lines.push(` Latest memory_write: ${fmtMem(latestEntry)}`);
624010
- }
624011
623827
  } catch {
624012
623828
  }
624013
623829
  }
624014
- lines.push("");
624015
- lines.push("Rules:");
624016
- lines.push(" 1. Do not tell the user 'memory is empty' or 'nothing has been stored' for this chat without first calling memory_search and memory_read on a relevant topic from the list above.");
624017
- lines.push(" 2. If the structured sections (cards/facts/sqlite/episodes) above did not surface what the user asked about, that is a scoring miss, not absence. Call memory_search with broader tokens or pick a topic above with memory_read.");
624018
- lines.push(" 3. The rolling-history block is base context; the cards/facts/episodes are retrieval-augmented. Treat them as the same memory, surfaced different ways.");
624019
- lines.push(" 4. For 'what is your oldest/earliest memory' or 'most recent memory' questions: answer directly from the 'Chronological anchors' lines above. Quote the timestamp and content. Do not call tools first and do not report 'empty'.");
624020
- lines.push(" 5. memory_search accepts natural-language time phrases inside the `query` argument or explicit `since`/`until`/`bucket` args. Examples: query='what did manitcor say yesterday', query='last 3 hours', query='earlier today', query='2 days ago', query='since 2026-05-15', query='between 2026-05-15 and 2026-05-16', query='oldest memory about github', query='most recent flux discussion'. Use these for chronological/'how far back' style queries instead of guessing - the tool parses the phrase, filters by time, and returns the right window.");
624021
- return lines.join("\n");
623830
+ const hasMemory = cardCount + factCount + userMemoryCount + topicCount > 0 || historyCount > 0;
623831
+ if (!hasMemory) return "";
623832
+ return [
623833
+ "### Memory Substrate (this chat)",
623834
+ `Available: ${cardCount} cards, ${factCount} facts, ${userMemoryCount} per-user memories, ${historyCount} rolling-history msgs, ${topicCount} memory_read topics.`,
623835
+ "Recall via memory_search (semantic similarity / graph traversal / episodes). For exact reads: memory_read(topic, key). The substrate is associative recall is by cue, not by date."
623836
+ ].join("\n");
624022
623837
  }
624023
623838
  buildTelegramConversationContextStream(sessionKey, msg, maxRecent = TELEGRAM_CONTEXT_RECENT_DEFAULT, salienceSignals = []) {
624024
623839
  this.ensureTelegramConversationLoaded(sessionKey);
@@ -625546,7 +625361,7 @@ ${list}` : "No shared group target is currently known for this sender. Ask in th
625546
625361
  return [
625547
625362
  "## Admin Telegram Omniscience (index only)",
625548
625363
  "One-way context for the authenticated admin private DM. Other Telegram sessions the bot has observed are listed below with one line each.",
625549
- "For details on a specific chat, use telegram_memory_search with the chat_id or topic — the always-loaded view is intentionally compact.",
625364
+ "For details on a specific chat, use memory_search (mode=episodes) with a topic keyword or chat_id — the always-loaded view is intentionally compact.",
625550
625365
  "Never inject admin/private DM content into public groups.",
625551
625366
  indexLines.join("\n")
625552
625367
  ].join("\n\n");
@@ -626523,11 +626338,7 @@ Join: ${newUrl}`);
626523
626338
  lastEditMs = now;
626524
626339
  const html = renderTelegramLiveProgressHTML(progressLines, accumulated);
626525
626340
  if (!html.trim()) return;
626526
- await this.editLiveMessage(
626527
- msg.chatId,
626528
- liveMessageId,
626529
- html
626530
- ).catch(() => {
626341
+ void this.editLiveMessage(msg.chatId, liveMessageId, html).catch(() => {
626531
626342
  });
626532
626343
  } else if (!liveMessageId && !liveMessagePromise && !msg.guestQueryId) {
626533
626344
  const html = renderTelegramLiveProgressHTML(progressLines, accumulated);
@@ -626543,7 +626354,6 @@ Join: ${newUrl}`);
626543
626354
  }).finally(() => {
626544
626355
  liveMessagePromise = null;
626545
626356
  });
626546
- await liveMessagePromise;
626547
626357
  }
626548
626358
  }
626549
626359
  }
@@ -626681,6 +626491,7 @@ ${conversationStream}`
626681
626491
  try {
626682
626492
  if (stream && typeof stream[Symbol.asyncIterator] === "function") {
626683
626493
  try {
626494
+ let lastTokenEmitMs = 0;
626684
626495
  for await (const chunk of stream) {
626685
626496
  if (chunk.type !== "content") continue;
626686
626497
  const piece = chunk.content;
@@ -626697,8 +626508,19 @@ ${conversationStream}`
626697
626508
  } else {
626698
626509
  this.bumpTelegramInferenceTokens(inferenceId, 1, 0);
626699
626510
  accumulated += piece;
626700
- const partial = extractPartialTelegramReplyJson(accumulated);
626701
- if (partial !== null) await onToken(partial);
626511
+ const now = Date.now();
626512
+ if (now - lastTokenEmitMs > 120) {
626513
+ lastTokenEmitMs = now;
626514
+ const partial = extractPartialTelegramReplyJson(accumulated);
626515
+ if (partial !== null) void onToken(partial);
626516
+ }
626517
+ }
626518
+ }
626519
+ const finalPartial = extractPartialTelegramReplyJson(accumulated);
626520
+ if (finalPartial !== null) {
626521
+ try {
626522
+ await onToken(finalPartial);
626523
+ } catch {
626702
626524
  }
626703
626525
  }
626704
626526
  } catch (err) {
@@ -630227,7 +630049,7 @@ ${caption}\r
630227
630049
  }
630228
630050
  }
630229
630051
  /** Make a Telegram Bot API call with rate-limit retry */
630230
- async apiCall(method, body) {
630052
+ async apiCall(method, body, _retryDepth = 0) {
630231
630053
  const url = `https://api.telegram.org/bot${this.botToken}/${method}`;
630232
630054
  const options2 = {
630233
630055
  method: "POST",
@@ -630245,9 +630067,13 @@ ${caption}\r
630245
630067
  const res = await fetch(url, options2);
630246
630068
  const data = await res.json();
630247
630069
  if (data["error_code"] === 429 && data["parameters"]?.retry_after) {
630248
- const waitSec = data["parameters"].retry_after;
630070
+ const waitSec = Math.min(3, data["parameters"].retry_after);
630071
+ const isLiveEdit = method === "editMessageText";
630072
+ if (isLiveEdit || _retryDepth >= 1) {
630073
+ return data;
630074
+ }
630249
630075
  await new Promise((r2) => setTimeout(r2, waitSec * 1e3));
630250
- return this.apiCall(method, body);
630076
+ return this.apiCall(method, body, _retryDepth + 1);
630251
630077
  }
630252
630078
  return data;
630253
630079
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.137",
3
+ "version": "1.0.139",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.137",
9
+ "version": "1.0.139",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.137",
3
+ "version": "1.0.139",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",