omnius 1.0.131 → 1.0.132

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
@@ -564387,6 +564387,7 @@ var init_command_registry = __esm({
564387
564387
  ["/telegram status", "Show Telegram bridge status"],
564388
564388
  ["/telegram stop", "Disconnect Telegram bridge"],
564389
564389
  ["/telegram mode auto|chat|action", "Set Telegram interaction routing: auto, fast chat, or action sub-agent"],
564390
+ ["/telegram subagents <1-5>", "Set global Telegram work-slot limit across all chats/groups"],
564390
564391
  ["/telegram auth", "Show a TUI-only one-time code for Telegram admin authentication"],
564391
564392
  ["/telegram auth cancel", "Cancel the pending Telegram admin authentication code"],
564392
564393
  ["/telegram bot <username> <text>", "Send a Bot API bot-to-bot message by @username"],
@@ -597970,6 +597971,31 @@ sleep 1
597970
597971
  renderInfo(`Telegram interaction mode set to ${c3.bold(requested)}${wantsLocalMode ? " (project)" : " (global)"}.`);
597971
597972
  return "handled";
597972
597973
  }
597974
+ if (parts[0] === "subagents" || parts[0] === "sub-agents" || parts[0] === "agents") {
597975
+ const requested = parts.slice(1).find((part) => !part.startsWith("--"));
597976
+ if (!requested) {
597977
+ const settings = ctx3.getTelegramSettings?.() ?? {};
597978
+ renderInfo(`Telegram sub-agent slots: ${c3.bold(String(settings.subAgents ?? 2))} global max (cap 5).`);
597979
+ renderInfo("Use /telegram subagents 1, /telegram subagents 2, ... up to 5.");
597980
+ return "handled";
597981
+ }
597982
+ const parsed = Number(requested);
597983
+ if (!Number.isFinite(parsed) || parsed < 1) {
597984
+ renderWarning("Usage: /telegram subagents <1-5> [--global]");
597985
+ return "handled";
597986
+ }
597987
+ const limit = Math.max(1, Math.min(5, Math.floor(parsed)));
597988
+ const hasGlobalFlagSubAgents = parts.includes("--global");
597989
+ const projectRootSubAgents = ctx3.repoRoot || process.cwd();
597990
+ const projectHasOmniusSubAgents = existsSync104(join117(projectRootSubAgents, ".omnius"));
597991
+ const wantsLocalSubAgents = hasGlobalFlagSubAgents ? false : isLocal || projectHasOmniusSubAgents;
597992
+ ctx3.saveTelegramSettings?.({ subAgents: limit, local: wantsLocalSubAgents });
597993
+ const activeLimit = ctx3.telegramSetSubAgentLimit?.(limit) ?? limit;
597994
+ renderInfo(
597995
+ `Telegram sub-agent slots set to ${c3.bold(String(activeLimit))} global max${parsed > 5 ? " (requested value capped at 5)" : ""}${wantsLocalSubAgents ? " (project)" : " (global)"}.`
597996
+ );
597997
+ return "handled";
597998
+ }
597973
597999
  if (parts[0] === "auth" || parts[0] === "authenticate") {
597974
598000
  if (parts[1] === "cancel") {
597975
598001
  const cancelled = ctx3.telegramCancelAdminAuth?.() ?? false;
@@ -598339,6 +598365,7 @@ sleep 1
598339
598365
  renderInfo(" /telegram stop Stop bridge");
598340
598366
  renderInfo(" /telegram status Show status");
598341
598367
  renderInfo(" /telegram mode auto|chat|action Set interaction routing profile");
598368
+ renderInfo(" /telegram subagents <1-5> Set global Telegram work-slot limit");
598342
598369
  renderInfo(" /telegram auth Show one-time admin auth code");
598343
598370
  renderInfo(" /telegram auth cancel Cancel pending admin auth code");
598344
598371
  renderInfo(" /telegram bot <username> <text> Send bot-to-bot message");
@@ -616665,6 +616692,11 @@ function buildTelegramRuntimeContext(now = /* @__PURE__ */ new Date(), repoRoot)
616665
616692
  function telegramSessionIdFromKey(sessionKey) {
616666
616693
  return `telegram-${createHash25("sha1").update(sessionKey).digest("hex").slice(0, 16)}`;
616667
616694
  }
616695
+ function normalizeTelegramSubAgentLimit(value2) {
616696
+ const parsed = typeof value2 === "number" ? value2 : typeof value2 === "string" && value2.trim() ? Number(value2.trim()) : TELEGRAM_SUB_AGENT_DEFAULT_LIMIT;
616697
+ if (!Number.isFinite(parsed)) return TELEGRAM_SUB_AGENT_DEFAULT_LIMIT;
616698
+ return Math.max(1, Math.min(TELEGRAM_SUB_AGENT_MAX_LIMIT, Math.floor(parsed)));
616699
+ }
616668
616700
  function selectTelegramFinalResponse(args) {
616669
616701
  const committedVisibleReply = cleanTelegramVisibleReply(args.visibleReplyText || "");
616670
616702
  if (committedVisibleReply) return committedVisibleReply;
@@ -617361,11 +617393,13 @@ function normalizeTelegramSendKind(rawKind, path12) {
617361
617393
  }
617362
617394
  return classifyMedia(path12) ?? "document";
617363
617395
  }
617364
- function renderTelegramStart(botUsername, adminId, mode = "auto", canReadAllGroupMessages) {
617396
+ function renderTelegramStart(botUsername, adminId, mode = "auto", canReadAllGroupMessages, maxSubAgents = TELEGRAM_SUB_AGENT_DEFAULT_LIMIT) {
617365
617397
  process.stdout.write(`
617366
617398
  ${c3.cyan("✈")} ${c3.bold("Telegram Bridge")} connected as @${botUsername}
617367
617399
  `);
617368
617400
  process.stdout.write(` ${c3.dim(`Interaction mode: ${mode}`)}
617401
+ `);
617402
+ process.stdout.write(` ${c3.dim(`Telegram work slots: ${maxSubAgents} global max (use /telegram subagents 1-${TELEGRAM_SUB_AGENT_MAX_LIMIT})`)}
617369
617403
  `);
617370
617404
  process.stdout.write(` ${c3.dim("Auto mode uses quick chat for conversational turns and sub-agents for action requests")}
617371
617405
  `);
@@ -617390,12 +617424,14 @@ function renderTelegramStart(botUsername, adminId, mode = "auto", canReadAllGrou
617390
617424
 
617391
617425
  `);
617392
617426
  }
617393
- function renderTelegramStatus(active, botUsername, adminId, activeSubAgents, mode = "auto", canReadAllGroupMessages) {
617427
+ function renderTelegramStatus(active, botUsername, adminId, activeSubAgents, mode = "auto", canReadAllGroupMessages, maxSubAgents = TELEGRAM_SUB_AGENT_DEFAULT_LIMIT, queuedSubAgentSessions = 0) {
617394
617428
  if (active) {
617395
617429
  process.stdout.write(`
617396
617430
  ${c3.green("●")} Telegram bridge: ${c3.bold("active")} (@${botUsername ?? "?"})
617397
617431
  `);
617398
617432
  process.stdout.write(` Mode: ${mode}
617433
+ `);
617434
+ process.stdout.write(` Telegram work slots: ${activeSubAgents ?? 0}/${maxSubAgents} active${queuedSubAgentSessions > 0 ? `, ${queuedSubAgentSessions} queued` : ""}
617399
617435
  `);
617400
617436
  process.stdout.write(` Group ingest: ${canReadAllGroupMessages ? "all delivered group messages" : "privacy-limited by Telegram/BotFather"}
617401
617437
  `);
@@ -617471,7 +617507,7 @@ function renderTelegramSubAgentError(username, error) {
617471
617507
  process.stdout.write(` ${c3.dim("│")} ${c3.magenta("✘")} @${username}: ${c3.dim(preview)}
617472
617508
  `);
617473
617509
  }
617474
- var TELEGRAM_TOOL_ACTION_GROUPS, TELEGRAM_TOOL_ACTION_GROUP, TELEGRAM_TOOL_MUTATING_GROUPS, DEFAULT_TELEGRAM_TOOL_GROUP_POLICY, TELEGRAM_TOOL_BUTTON_LABELS, TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, TELEGRAM_PUBLIC_SOUL_PROFILE, TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT, TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT, TELEGRAM_PUBLIC_VISION_STACK_CONTRACT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_EXTERNAL_ACQUISITION_CONTRACT, TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT, TELEGRAM_STUCK_SELF_TALK_PREFIXES, TELEGRAM_CHAT_HISTORY_LIMIT, TELEGRAM_CONTEXT_RECENT_DEFAULT, TELEGRAM_CONTEXT_LINE_LIMIT, TELEGRAM_CONTEXT_SAMPLE_LIMIT, TELEGRAM_MEMORY_CARD_LIMIT, TELEGRAM_MEMORY_NOTE_LIMIT, TELEGRAM_ASSOCIATIVE_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_USER_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_ACTION_LIMIT, TELEGRAM_ASSOCIATIVE_RELATION_LIMIT, TELEGRAM_MEMORY_STOPWORDS, TELEGRAM_MEMORY_GENERIC_QUERY_TOKENS, TELEGRAM_SUB_AGENT_BOUNDED_OPTIONS, TELEGRAM_PUBLIC_HELP_COMMANDS2, TELEGRAM_REMINDER_SLASH_COMMANDS, TELEGRAM_REFLECTION_SLASH_COMMANDS, TELEGRAM_PUBLIC_BOT_COMMAND_NAMES, TELEGRAM_IMAGE_EXTENSIONS, MEDIA_CACHE_TTL_MS, TELEGRAM_CHANNEL_DMN_SWEEP_MS, TELEGRAM_CHANNEL_DMN_IDLE_AFTER_MS, TELEGRAM_CHANNEL_DMN_MIN_INTERVAL_MS, TELEGRAM_CHANNEL_DMN_MIN_MESSAGES, TELEGRAM_ALLOWED_UPDATES, TELEGRAM_PUBLIC_TOOL_QUOTAS, TelegramBridge;
617510
+ var TELEGRAM_TOOL_ACTION_GROUPS, TELEGRAM_TOOL_ACTION_GROUP, TELEGRAM_TOOL_MUTATING_GROUPS, DEFAULT_TELEGRAM_TOOL_GROUP_POLICY, TELEGRAM_TOOL_BUTTON_LABELS, TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, TELEGRAM_PUBLIC_SOUL_PROFILE, TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT, TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT, TELEGRAM_PUBLIC_VISION_STACK_CONTRACT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_EXTERNAL_ACQUISITION_CONTRACT, TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT, TELEGRAM_STUCK_SELF_TALK_PREFIXES, TELEGRAM_CHAT_HISTORY_LIMIT, TELEGRAM_CONTEXT_RECENT_DEFAULT, TELEGRAM_CONTEXT_LINE_LIMIT, TELEGRAM_CONTEXT_SAMPLE_LIMIT, TELEGRAM_MEMORY_CARD_LIMIT, TELEGRAM_MEMORY_NOTE_LIMIT, TELEGRAM_ASSOCIATIVE_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_USER_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_ACTION_LIMIT, TELEGRAM_ASSOCIATIVE_RELATION_LIMIT, TELEGRAM_MEMORY_STOPWORDS, TELEGRAM_MEMORY_GENERIC_QUERY_TOKENS, TELEGRAM_SUB_AGENT_BOUNDED_OPTIONS, TELEGRAM_SUB_AGENT_DEFAULT_LIMIT, TELEGRAM_SUB_AGENT_MAX_LIMIT, TELEGRAM_PUBLIC_HELP_COMMANDS2, TELEGRAM_REMINDER_SLASH_COMMANDS, TELEGRAM_REFLECTION_SLASH_COMMANDS, TELEGRAM_PUBLIC_BOT_COMMAND_NAMES, TELEGRAM_IMAGE_EXTENSIONS, MEDIA_CACHE_TTL_MS, TELEGRAM_CHANNEL_DMN_SWEEP_MS, TELEGRAM_CHANNEL_DMN_IDLE_AFTER_MS, TELEGRAM_CHANNEL_DMN_MIN_INTERVAL_MS, TELEGRAM_CHANNEL_DMN_MIN_MESSAGES, TELEGRAM_ALLOWED_UPDATES, TELEGRAM_PUBLIC_TOOL_QUOTAS, TelegramBridge;
617475
617511
  var init_telegram_bridge = __esm({
617476
617512
  "packages/cli/src/tui/telegram-bridge.ts"() {
617477
617513
  "use strict";
@@ -617850,6 +617886,8 @@ External acquisition contract:
617850
617886
  bruteForceMaxCycles: 0,
617851
617887
  allowTurnExtension: false
617852
617888
  };
617889
+ TELEGRAM_SUB_AGENT_DEFAULT_LIMIT = 2;
617890
+ TELEGRAM_SUB_AGENT_MAX_LIMIT = 5;
617853
617891
  TELEGRAM_PUBLIC_HELP_COMMANDS2 = /* @__PURE__ */ new Set(["help", "start", "auth", "call"]);
617854
617892
  TELEGRAM_REMINDER_SLASH_COMMANDS = /* @__PURE__ */ new Set(["remind", "reminder", "reminders"]);
617855
617893
  TELEGRAM_REFLECTION_SLASH_COMMANDS = /* @__PURE__ */ new Set(["reflect", "reflection", "daydream", "dream"]);
@@ -617884,6 +617922,7 @@ External acquisition contract:
617884
617922
  this.telegramConversationDir = resolve45(repoRoot || ".", ".omnius", "telegram-conversations");
617885
617923
  this.telegramSqlitePath = resolve45(repoRoot || ".", ".omnius", "telegram.sqlite");
617886
617924
  this.telegramToolButtonDir = resolve45(repoRoot || ".", ".omnius", "telegram-tool-buttons");
617925
+ this.state.maxSubAgents = normalizeTelegramSubAgentLimit(resolveSettings(repoRoot || ".").telegramSubAgents);
617887
617926
  this.hydrateTelegramCommandMap(buildTelegramBotCommands({ scope: "admin" }));
617888
617927
  }
617889
617928
  botToken;
@@ -617906,7 +617945,9 @@ External acquisition contract:
617906
617945
  startedAt: "",
617907
617946
  messagesReceived: 0,
617908
617947
  messagesSent: 0,
617909
- activeSubAgents: 0
617948
+ activeSubAgents: 0,
617949
+ maxSubAgents: TELEGRAM_SUB_AGENT_DEFAULT_LIMIT,
617950
+ queuedSubAgentSessions: 0
617910
617951
  };
617911
617952
  /** Admin user ID — if set, messages from this user get full memory access */
617912
617953
  adminUserId = null;
@@ -617916,6 +617957,16 @@ External acquisition contract:
617916
617957
  telegramSubAgentContextBuffers = /* @__PURE__ */ new Map();
617917
617958
  /** Active direct chat completions, counted with Telegram activity in the TUI */
617918
617959
  activeChatViews = /* @__PURE__ */ new Set();
617960
+ /**
617961
+ * Global Telegram work admission. This is intentionally broader than
617962
+ * this.subAgents: router inference, fast-chat completions, and action
617963
+ * runners all consume a slot because all of them can block local model
617964
+ * capacity and flood the TUI.
617965
+ */
617966
+ telegramActiveWorkSessions = /* @__PURE__ */ new Set();
617967
+ /** Queued Telegram sessions waiting for a global work slot. */
617968
+ telegramQueuedSessionWork = /* @__PURE__ */ new Map();
617969
+ telegramDispatchQueuedTimer = null;
617919
617970
  /** Lightweight chat history by chat/guest session key */
617920
617971
  chatHistory = /* @__PURE__ */ new Map();
617921
617972
  /** Participant and tone state by chat/guest session key */
@@ -617965,7 +618016,7 @@ External acquisition contract:
617965
618016
  * Live telemetry of every in-flight Ollama call originating from the
617966
618017
  * bridge. Lets the operator see WHY multiple GPUs are spun up at once
617967
618018
  * and HOW each call is progressing — which is the only way to debug a
617968
- * 180s hard-deadline firing event without grepping logs.
618019
+ * router hard-deadline firing event without grepping logs.
617969
618020
  *
617970
618021
  * Each entry tracks:
617971
618022
  * - kind: router | chat-fast-path | followup | sub-agent
@@ -618019,6 +618070,7 @@ External acquisition contract:
618019
618070
  ]);
618020
618071
  /** TUI agent-view callbacks for Telegram sub-agent registration. */
618021
618072
  subAgentViewCallbacks = null;
618073
+ rawSubAgentViewCallbacks = null;
618022
618074
  /** Callback to get active call session URL (wired from interactive.ts) */
618023
618075
  callUrlGetter = null;
618024
618076
  /** Callback to start a call session and return the URL (wired from interactive.ts) */
@@ -618029,6 +618081,10 @@ External acquisition contract:
618029
618081
  callStartInProgress = false;
618030
618082
  /** Callback to write content into the scrollable TUI waterfall area (wired from interactive.ts) */
618031
618083
  writeContent = null;
618084
+ pendingTuiWrites = [];
618085
+ pendingTuiWriteTimer = null;
618086
+ pendingSubAgentViewWrites = /* @__PURE__ */ new Map();
618087
+ pendingSubAgentViewWriteTimer = null;
618032
618088
  /** Media cache — fileUniqueId → cache entry */
618033
618089
  mediaCache = /* @__PURE__ */ new Map();
618034
618090
  /** Media cache directory */
@@ -618076,6 +618132,15 @@ External acquisition contract:
618076
618132
  getInteractionMode() {
618077
618133
  return this.interactionMode;
618078
618134
  }
618135
+ setSubAgentLimit(limit) {
618136
+ const normalized = normalizeTelegramSubAgentLimit(limit);
618137
+ this.state.maxSubAgents = normalized;
618138
+ this.dispatchQueuedTelegramSessionWorkSoon();
618139
+ return normalized;
618140
+ }
618141
+ getSubAgentLimit() {
618142
+ return normalizeTelegramSubAgentLimit(this.state.maxSubAgents);
618143
+ }
618079
618144
  setContextWindowSize(size) {
618080
618145
  this.contextWindowSize = Number.isFinite(size) && size > 0 ? Math.trunc(size) : 0;
618081
618146
  }
@@ -618106,7 +618171,19 @@ External acquisition contract:
618106
618171
  this.adminAuthHandler = handler;
618107
618172
  }
618108
618173
  setSubAgentViewCallbacks(callbacks) {
618109
- this.subAgentViewCallbacks = callbacks;
618174
+ this.rawSubAgentViewCallbacks = callbacks;
618175
+ this.subAgentViewCallbacks = {
618176
+ onRegister: (...args) => callbacks.onRegister(...args),
618177
+ onWrite: (id, text) => this.telegramViewWrite(id, text),
618178
+ onStatus: (...args) => {
618179
+ this.flushTelegramViewWrites();
618180
+ callbacks.onStatus(...args);
618181
+ },
618182
+ onComplete: (...args) => {
618183
+ this.flushTelegramViewWrites();
618184
+ callbacks.onComplete(...args);
618185
+ }
618186
+ };
618110
618187
  }
618111
618188
  /** Register callback to get active call URL for /call button forwarding */
618112
618189
  setCallUrlGetter(getter) {
@@ -618132,7 +618209,12 @@ External acquisition contract:
618132
618209
  return this.polling;
618133
618210
  }
618134
618211
  get stats() {
618135
- return { ...this.state, activeSubAgents: this.activeTelegramInteractionCount() };
618212
+ return {
618213
+ ...this.state,
618214
+ activeSubAgents: this.activeTelegramInteractionCount(),
618215
+ maxSubAgents: this.getSubAgentLimit(),
618216
+ queuedSubAgentSessions: this.telegramQueuedSessionWork.size
618217
+ };
618136
618218
  }
618137
618219
  get botUsername() {
618138
618220
  return this.state.botUsername;
@@ -618414,10 +618496,61 @@ No scoped reflection artifact exists yet for this chat. Use <code>/reflect</code
618414
618496
  }
618415
618497
  /** Write to the scrollable TUI waterfall area (respects status bar scroll region) */
618416
618498
  tuiWrite(fn) {
618499
+ this.pendingTuiWrites.push(fn);
618500
+ if (this.pendingTuiWriteTimer) return;
618501
+ this.pendingTuiWriteTimer = setTimeout(() => this.flushTelegramTuiWrites(), 0);
618502
+ if (typeof this.pendingTuiWriteTimer.unref === "function") {
618503
+ this.pendingTuiWriteTimer.unref();
618504
+ }
618505
+ }
618506
+ flushTelegramTuiWrites() {
618507
+ if (this.pendingTuiWriteTimer) {
618508
+ clearTimeout(this.pendingTuiWriteTimer);
618509
+ this.pendingTuiWriteTimer = null;
618510
+ }
618511
+ const batch2 = this.pendingTuiWrites.splice(0);
618512
+ if (batch2.length === 0) return;
618513
+ const runBatch = () => {
618514
+ for (const fn of batch2) {
618515
+ try {
618516
+ fn();
618517
+ } catch {
618518
+ }
618519
+ }
618520
+ };
618417
618521
  if (this.writeContent) {
618418
- this.writeContent(fn);
618522
+ this.writeContent(runBatch);
618419
618523
  } else {
618420
- fn();
618524
+ runBatch();
618525
+ }
618526
+ }
618527
+ telegramViewWrite(id, text) {
618528
+ const callbacks = this.rawSubAgentViewCallbacks;
618529
+ if (!callbacks) return;
618530
+ const queue = this.pendingSubAgentViewWrites.get(id) ?? [];
618531
+ queue.push(text);
618532
+ this.pendingSubAgentViewWrites.set(id, queue);
618533
+ if (this.pendingSubAgentViewWriteTimer) return;
618534
+ this.pendingSubAgentViewWriteTimer = setTimeout(() => this.flushTelegramViewWrites(), 100);
618535
+ if (typeof this.pendingSubAgentViewWriteTimer.unref === "function") {
618536
+ this.pendingSubAgentViewWriteTimer.unref();
618537
+ }
618538
+ }
618539
+ flushTelegramViewWrites() {
618540
+ if (this.pendingSubAgentViewWriteTimer) {
618541
+ clearTimeout(this.pendingSubAgentViewWriteTimer);
618542
+ this.pendingSubAgentViewWriteTimer = null;
618543
+ }
618544
+ const callbacks = this.rawSubAgentViewCallbacks;
618545
+ if (!callbacks || this.pendingSubAgentViewWrites.size === 0) {
618546
+ this.pendingSubAgentViewWrites.clear();
618547
+ return;
618548
+ }
618549
+ const batch2 = this.pendingSubAgentViewWrites;
618550
+ this.pendingSubAgentViewWrites = /* @__PURE__ */ new Map();
618551
+ for (const [id, lines] of batch2) {
618552
+ if (lines.length === 0) continue;
618553
+ callbacks.onWrite(id, lines.join("\n"));
618421
618554
  }
618422
618555
  }
618423
618556
  sessionKeyForMessage(msg) {
@@ -618425,10 +618558,99 @@ No scoped reflection artifact exists yet for this chat. Use <code>/reflect</code
618425
618558
  return `chat:${String(msg.chatId)}`;
618426
618559
  }
618427
618560
  activeTelegramInteractionCount() {
618428
- return this.subAgents.size + this.activeChatViews.size;
618561
+ return Math.max(
618562
+ this.telegramActiveWorkSessions.size,
618563
+ this.subAgents.size + this.activeChatViews.size
618564
+ );
618429
618565
  }
618430
618566
  refreshActiveTelegramInteractionCount() {
618431
618567
  this.state.activeSubAgents = this.activeTelegramInteractionCount();
618568
+ this.state.maxSubAgents = this.getSubAgentLimit();
618569
+ this.state.queuedSubAgentSessions = this.telegramQueuedSessionWork.size;
618570
+ }
618571
+ telegramWorkCapacityAvailable() {
618572
+ return this.telegramActiveWorkSessions.size < this.getSubAgentLimit();
618573
+ }
618574
+ dispatchQueuedTelegramSessionWorkSoon() {
618575
+ if (this.telegramDispatchQueuedTimer) return;
618576
+ this.telegramDispatchQueuedTimer = setTimeout(() => this.dispatchQueuedTelegramSessionWork(), 0);
618577
+ if (typeof this.telegramDispatchQueuedTimer.unref === "function") {
618578
+ this.telegramDispatchQueuedTimer.unref();
618579
+ }
618580
+ }
618581
+ dispatchQueuedTelegramSessionWork() {
618582
+ if (this.telegramDispatchQueuedTimer) {
618583
+ clearTimeout(this.telegramDispatchQueuedTimer);
618584
+ this.telegramDispatchQueuedTimer = null;
618585
+ }
618586
+ while (this.telegramWorkCapacityAvailable()) {
618587
+ const next = [...this.telegramQueuedSessionWork.values()].filter((work) => !this.telegramActiveWorkSessions.has(work.sessionKey)).sort((a2, b) => a2.lastSpokenAtMs - b.lastSpokenAtMs || a2.enqueuedAtMs - b.enqueuedAtMs)[0];
618588
+ if (!next) break;
618589
+ this.telegramQueuedSessionWork.delete(next.sessionKey);
618590
+ this.startTelegramSessionWork(next);
618591
+ }
618592
+ this.refreshActiveTelegramInteractionCount();
618593
+ }
618594
+ scheduleTelegramSessionWork(msg, toolContext) {
618595
+ const sessionKey = this.sessionKeyForMessage(msg);
618596
+ const now = Date.now();
618597
+ const existing = this.telegramQueuedSessionWork.get(sessionKey);
618598
+ if (this.telegramWorkCapacityAvailable() && !this.telegramActiveWorkSessions.has(sessionKey)) {
618599
+ if (existing) this.telegramQueuedSessionWork.delete(sessionKey);
618600
+ this.startTelegramSessionWork({
618601
+ sessionKey,
618602
+ msg,
618603
+ toolContext,
618604
+ enqueuedAtMs: existing?.enqueuedAtMs ?? now,
618605
+ lastSpokenAtMs: now,
618606
+ messageCount: (existing?.messageCount ?? 0) + 1
618607
+ });
618608
+ return;
618609
+ }
618610
+ this.telegramQueuedSessionWork.set(sessionKey, {
618611
+ sessionKey,
618612
+ msg,
618613
+ toolContext,
618614
+ enqueuedAtMs: existing?.enqueuedAtMs ?? now,
618615
+ lastSpokenAtMs: now,
618616
+ messageCount: (existing?.messageCount ?? 0) + 1
618617
+ });
618618
+ this.refreshActiveTelegramInteractionCount();
618619
+ this.tuiWrite(() => renderTelegramSubAgentEvent(
618620
+ msg.username,
618621
+ `queued Telegram work for ${msg.chatTitle || msg.chatType}; active ${this.telegramActiveWorkSessions.size}/${this.getSubAgentLimit()}, queued ${this.telegramQueuedSessionWork.size}`
618622
+ ));
618623
+ }
618624
+ startTelegramSessionWork(work) {
618625
+ this.telegramActiveWorkSessions.add(work.sessionKey);
618626
+ this.refreshActiveTelegramInteractionCount();
618627
+ void this.processTelegramMessageWork(work.msg, work.toolContext).catch((err) => {
618628
+ this.tuiWrite(() => renderWarning(`Telegram sub-agent error: ${err instanceof Error ? err.message : String(err)}`));
618629
+ }).finally(() => {
618630
+ this.telegramActiveWorkSessions.delete(work.sessionKey);
618631
+ this.refreshActiveTelegramInteractionCount();
618632
+ this.dispatchQueuedTelegramSessionWorkSoon();
618633
+ });
618634
+ }
618635
+ takeQueuedTelegramSessionWork(sessionKey) {
618636
+ const queued = this.telegramQueuedSessionWork.get(sessionKey);
618637
+ if (!queued) return void 0;
618638
+ this.telegramQueuedSessionWork.delete(sessionKey);
618639
+ this.refreshActiveTelegramInteractionCount();
618640
+ return queued;
618641
+ }
618642
+ fallbackTelegramRouterDecision(msg, toolContext, err) {
618643
+ const forcedRoute = this.interactionMode === "chat" || this.interactionMode === "action" ? this.interactionMode : null;
618644
+ const errMsg = err instanceof Error ? err.message : String(err);
618645
+ return {
618646
+ route: forcedRoute ?? (msg.chatType === "private" ? "chat" : "action"),
618647
+ shouldReply: false,
618648
+ confidence: 0,
618649
+ reason: `router unavailable; retained as context without replying (${errMsg.slice(0, 160)})`,
618650
+ source: "inference-unavailable",
618651
+ silentDisposition: "retained as context without replying because the router did not settle",
618652
+ diagnosticNote: `router failure after queue admission: ${errMsg.slice(0, 240)}; tool_context=${toolContext}`
618653
+ };
618432
618654
  }
618433
618655
  canUseChatActions(msg) {
618434
618656
  return !msg.guestQueryId && (typeof msg.chatId === "number" || String(msg.chatId).startsWith("@"));
@@ -619568,7 +619790,7 @@ ${mediaContext}` : ""
619568
619790
  async runTelegramChannelDmnForSession(sessionKey, reason = "idle", nowMs = Date.now(), force = false) {
619569
619791
  if (!this.repoRoot) return null;
619570
619792
  if (this.channelDmnRunning.has(sessionKey)) return null;
619571
- if (this.subAgents.has(sessionKey)) return null;
619793
+ if (this.subAgents.has(sessionKey) || this.telegramActiveWorkSessions.has(sessionKey)) return null;
619572
619794
  const input = this.buildTelegramChannelDaydreamInput(sessionKey, nowMs);
619573
619795
  if (!input) return null;
619574
619796
  if (input.chatType === "private" && !force) return null;
@@ -621392,7 +621614,7 @@ ${lines.join("\n")}`);
621392
621614
  // ─────────────────────────────────────────────────────────────────
621393
621615
  // Observable inference — streams chatCompletion-shaped calls so the
621394
621616
  // operator can SEE what's happening during a long-running router or
621395
- // chat-fast-path call instead of waiting 180s for a hard-deadline.
621617
+ // chat-fast-path call instead of waiting for a router hard-deadline.
621396
621618
  // ─────────────────────────────────────────────────────────────────
621397
621619
  /**
621398
621620
  * Wrap a chatCompletion-shaped call so the bridge can observe its token
@@ -621796,14 +622018,14 @@ ${retryText}`,
621796
622018
  * in-flight promise, and on completion fire any queued trailing call.
621797
622019
  */
621798
622020
  startCoalescedTelegramRouterCall(sessionKey, msg, toolContext) {
621799
- const HARD_DEADLINE_MS = 18e4;
622021
+ const HARD_DEADLINE_MS = this.telegramRouterHardDeadlineMs();
621800
622022
  const inner = this.inferTelegramInteractionDecision(msg, toolContext);
621801
622023
  const promise = new Promise((resolve54, reject) => {
621802
622024
  let settled = false;
621803
622025
  const guard = setTimeout(() => {
621804
622026
  if (settled) return;
621805
622027
  settled = true;
621806
- reject(new Error("router-coalescer: hard deadline exceeded (180s); inner inference did not settle"));
622028
+ reject(new Error(`router-coalescer: hard deadline exceeded (${Math.round(HARD_DEADLINE_MS / 1e3)}s); inner inference did not settle`));
621807
622029
  }, HARD_DEADLINE_MS);
621808
622030
  if (typeof guard.unref === "function") guard.unref();
621809
622031
  inner.then(
@@ -621841,6 +622063,11 @@ ${retryText}`,
621841
622063
  promise.then(onSettled, onSettled);
621842
622064
  return promise;
621843
622065
  }
622066
+ telegramRouterHardDeadlineMs() {
622067
+ const raw = Number.parseInt(process.env["OMNIUS_TG_ROUTER_HARD_DEADLINE_MS"] ?? "", 10);
622068
+ if (Number.isFinite(raw) && raw >= 5e3 && raw <= 18e4) return raw;
622069
+ return 6e4;
622070
+ }
621844
622071
  /**
621845
622072
  * Forcibly cancel every in-flight + trailing router-coalescer entry.
621846
622073
  * Used on bridge stop() and by the watchdog if it detects the coalescer
@@ -621889,11 +622116,11 @@ ${retryText}`,
621889
622116
  * the iterator, and telegramObservableInference falls back to the
621890
622117
  * non-streaming chatCompletion path. This gives operators a clean
621891
622118
  * "stream silent for 60s, falling back" signal instead of the opaque
621892
- * 180s coalescer hard-deadline.
622119
+ * coalescer hard-deadline.
621893
622120
  *
621894
622121
  * Default 60s — comfortably longer than a healthy cold-load of a 35B
621895
622122
  * model on a warm VRAM cache (typically <30s) but short enough to
621896
- * surface a real wedge before the 180s coalescer fires. Override via
622123
+ * surface a real wedge before the coalescer fires. Override via
621897
622124
  * OMNIUS_TG_STREAM_INACTIVITY_MS (clamped to [10s, 5min]).
621898
622125
  */
621899
622126
  telegramStreamInactivityMs() {
@@ -621963,7 +622190,9 @@ ${retryText}`,
621963
622190
  } catch {
621964
622191
  }
621965
622192
  this.subAgents.delete(sessionKey);
622193
+ this.telegramActiveWorkSessions.delete(sessionKey);
621966
622194
  this.refreshActiveTelegramInteractionCount();
622195
+ this.dispatchQueuedTelegramSessionWorkSoon();
621967
622196
  this.tuiWrite(() => renderTelegramSubAgentEvent(
621968
622197
  agent.username,
621969
622198
  `watchdog: aborted stale sub-agent (idle ${Math.round((now - agent.lastEditMs) / 1e3)}s without completion)`
@@ -621989,7 +622218,7 @@ ${retryText}`,
621989
622218
  privateChannel: !isGroup,
621990
622219
  directSignal: addressesBot,
621991
622220
  replyToAgent: this.telegramMessageRepliesToBot(msg),
621992
- activeAgent: this.subAgents.has(sessionKey),
622221
+ activeAgent: this.subAgents.has(sessionKey) || this.telegramActiveWorkSessions.has(sessionKey),
621993
622222
  forceAnalyze: daydreamForceCheck
621994
622223
  });
621995
622224
  if (!config) {
@@ -622567,7 +622796,9 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
622567
622796
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
622568
622797
  messagesReceived: 0,
622569
622798
  messagesSent: 0,
622570
- activeSubAgents: 0
622799
+ activeSubAgents: 0,
622800
+ maxSubAgents: this.getSubAgentLimit(),
622801
+ queuedSubAgentSessions: 0
622571
622802
  };
622572
622803
  this.botUserId = typeof me.result?.id === "number" ? me.result.id : this.botUserId;
622573
622804
  this.polling = true;
@@ -622657,6 +622888,14 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
622657
622888
  this.stopTelegramSubAgentWatchdog();
622658
622889
  this.cancelTelegramRouterSessionState("bridge stop");
622659
622890
  this.clearAllTelegramSubAgentContextBuffers();
622891
+ if (this.telegramDispatchQueuedTimer) {
622892
+ clearTimeout(this.telegramDispatchQueuedTimer);
622893
+ this.telegramDispatchQueuedTimer = null;
622894
+ }
622895
+ this.telegramQueuedSessionWork.clear();
622896
+ this.telegramActiveWorkSessions.clear();
622897
+ this.flushTelegramViewWrites();
622898
+ this.flushTelegramTuiWrites();
622660
622899
  this.telegramActiveInferences.clear();
622661
622900
  if (this.telegramSqliteDb && this.telegramSqliteDb !== false) {
622662
622901
  try {
@@ -622988,8 +623227,23 @@ Join: ${newUrl}`);
622988
623227
  await this.enqueueTelegramMessageForExistingSubAgent(msg, existing);
622989
623228
  return;
622990
623229
  }
623230
+ this.scheduleTelegramSessionWork(msg, toolContext);
623231
+ }
623232
+ async processTelegramMessageWork(msg, toolContext) {
623233
+ const sessionKey = this.sessionKeyForMessage(msg);
623234
+ const isAdminDM = toolContext === "telegram-admin-dm";
623235
+ const existing = this.subAgents.get(sessionKey);
623236
+ if (existing && !existing.aborted) {
623237
+ await this.enqueueTelegramMessageForExistingSubAgent(msg, existing);
623238
+ return;
623239
+ }
622991
623240
  const attentionViewId = this.registerTelegramAttentionView(msg, toolContext);
622992
- const decision2 = await this.inferTelegramInteractionDecisionCoalesced(msg, toolContext);
623241
+ let decision2;
623242
+ try {
623243
+ decision2 = await this.inferTelegramInteractionDecisionCoalesced(msg, toolContext);
623244
+ } catch (err) {
623245
+ decision2 = this.fallbackTelegramRouterDecision(msg, toolContext, err);
623246
+ }
622993
623247
  this.deliverTelegramAttentionDecision(
622994
623248
  sessionKey,
622995
623249
  msg,
@@ -623061,6 +623315,14 @@ Join: ${newUrl}`);
623061
623315
  this.subAgentViewCallbacks?.onWrite(subAgent.viewId, replyEdge);
623062
623316
  }
623063
623317
  this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `✈ Telegram message from @${msg.username}: ${msg.text}`);
623318
+ const queuedForSameSession = this.takeQueuedTelegramSessionWork(sessionKey);
623319
+ if (queuedForSameSession) {
623320
+ await this.enqueueTelegramMessageForExistingSubAgent(queuedForSameSession.msg, subAgent);
623321
+ this.subAgentViewCallbacks?.onWrite(
623322
+ subAgent.viewId,
623323
+ `merged queued session work (${queuedForSameSession.messageCount} message${queuedForSameSession.messageCount === 1 ? "" : "s"}) before runner start`
623324
+ );
623325
+ }
623064
623326
  if (this.canUseChatActions(msg)) {
623065
623327
  subAgent.typingInterval = this.startTypingIndicator(msg.chatId);
623066
623328
  }
@@ -657329,10 +657591,12 @@ Log: ${nexusLogPath}`)
657329
657591
  }
657330
657592
  const source = scope === "global" ? globalSettings : projectSettings;
657331
657593
  const mode = source.telegramMode ?? savedSettings.telegramMode ?? "auto";
657594
+ const subAgents = typeof source.telegramSubAgents === "number" ? source.telegramSubAgents : typeof savedSettings.telegramSubAgents === "number" ? savedSettings.telegramSubAgents : 2;
657332
657595
  return {
657333
657596
  key: nonEmptyTelegramSetting(source.telegramKey),
657334
657597
  admin: nonEmptyTelegramSetting(source.telegramAdmin),
657335
657598
  mode,
657599
+ subAgents,
657336
657600
  keyScope: scope
657337
657601
  };
657338
657602
  };
@@ -657942,6 +658206,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
657942
658206
  telegramBridge.setContextWindowSize(resolvedContextWindowSize);
657943
658207
  }
657944
658208
  telegramBridge.setInteractionMode(savedSettings.telegramMode ?? "auto");
658209
+ telegramBridge.setSubAgentLimit(telegramSettingsForScope(scope).subAgents ?? 2);
657945
658210
  telegramBridge.setTelegramToolPolicy(savedSettings.telegramToolPolicy);
657946
658211
  telegramBridge.setMetricsProvider(() => statusBar?.getMetricsSnapshot());
657947
658212
  if (adminId) {
@@ -658076,7 +658341,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
658076
658341
  telegramBridge.botUsername,
658077
658342
  adminId,
658078
658343
  savedSettings.telegramMode ?? "auto",
658079
- telegramBridge.stats.canReadAllGroupMessages
658344
+ telegramBridge.stats.canReadAllGroupMessages,
658345
+ telegramBridge.stats.maxSubAgents
658080
658346
  )
658081
658347
  );
658082
658348
  showPrompt();
@@ -658109,10 +658375,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
658109
658375
  if (settings.mode !== void 0) {
658110
658376
  target.telegramMode = settings.mode;
658111
658377
  }
658378
+ if (settings.subAgents !== void 0) {
658379
+ target.telegramSubAgents = settings.subAgents;
658380
+ }
658112
658381
  const payload = {
658113
658382
  ...settings.key !== void 0 ? { telegramKey: settings.key } : {},
658114
658383
  ...settings.admin !== void 0 ? { telegramAdmin: settings.admin === null ? "" : settings.admin } : {},
658115
- ...settings.mode !== void 0 ? { telegramMode: settings.mode } : {}
658384
+ ...settings.mode !== void 0 ? { telegramMode: settings.mode } : {},
658385
+ ...settings.subAgents !== void 0 ? { telegramSubAgents: settings.subAgents } : {}
658116
658386
  };
658117
658387
  if (targetScope === "project") {
658118
658388
  saveProjectSettings(repoRoot, payload);
@@ -658142,10 +658412,16 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
658142
658412
  savedSettings.telegramMode = mode;
658143
658413
  telegramBridge?.setInteractionMode(mode);
658144
658414
  },
658415
+ telegramSetSubAgentLimit(limit) {
658416
+ savedSettings.telegramSubAgents = limit;
658417
+ return telegramBridge?.setSubAgentLimit(limit) ?? Math.max(1, Math.min(5, Math.floor(limit)));
658418
+ },
658145
658419
  telegramStatus() {
658146
658420
  const active = telegramBridge?.isActive ?? false;
658147
658421
  const botUser = active ? telegramBridge?.botUsername : void 0;
658148
658422
  const subAgents = active ? telegramBridge?.stats.activeSubAgents : void 0;
658423
+ const maxSubAgents = active ? telegramBridge?.stats.maxSubAgents : telegramSettingsForScope(activeTelegramSettingsScope ?? "project").subAgents ?? 2;
658424
+ const queuedSubAgents = active ? telegramBridge?.stats.queuedSubAgentSessions : 0;
658149
658425
  writeContent(
658150
658426
  () => renderTelegramStatus(
658151
658427
  active,
@@ -658153,7 +658429,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
658153
658429
  telegramSettingsForScope(activeTelegramSettingsScope ?? "project").admin,
658154
658430
  subAgents,
658155
658431
  savedSettings.telegramMode ?? "auto",
658156
- active ? telegramBridge?.stats.canReadAllGroupMessages : void 0
658432
+ active ? telegramBridge?.stats.canReadAllGroupMessages : void 0,
658433
+ maxSubAgents,
658434
+ queuedSubAgents
658157
658435
  )
658158
658436
  );
658159
658437
  },
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.131",
3
+ "version": "1.0.132",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.131",
9
+ "version": "1.0.132",
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.131",
3
+ "version": "1.0.132",
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",