omnius 1.0.209 → 1.0.211

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
@@ -284705,6 +284705,7 @@ async function launchService() {
284705
284705
  SCRAPE_REQUIRE_AUTH: "0"
284706
284706
  }
284707
284707
  });
284708
+ serviceProcess.unref();
284708
284709
  const cleanupService = () => {
284709
284710
  if (serviceProcess && serviceProcess.pid && !serviceProcess.killed) {
284710
284711
  try {
@@ -284958,6 +284959,7 @@ var init_browser_action = __esm({
284958
284959
  await apiCall("/session/close");
284959
284960
  } catch {
284960
284961
  }
284962
+ killBrowserActionServicePort();
284961
284963
  activeSessionId = null;
284962
284964
  activeSessionHeadless = null;
284963
284965
  activeSessionUrl = null;
@@ -561827,6 +561829,30 @@ ${blob}
561827
561829
  _buildToolFingerprint(name10, args) {
561828
561830
  return `${name10}:${this._buildExactArgsKey(args)}`;
561829
561831
  }
561832
+ _dedupeToolCallsForResponse(toolCalls, turn) {
561833
+ if (toolCalls.length <= 1)
561834
+ return toolCalls;
561835
+ const seen = /* @__PURE__ */ new Set();
561836
+ const deduped = [];
561837
+ let dropped = 0;
561838
+ for (const tc of toolCalls) {
561839
+ const fp = this._buildToolFingerprint(tc.name, tc.arguments ?? {});
561840
+ if (seen.has(fp)) {
561841
+ dropped++;
561842
+ continue;
561843
+ }
561844
+ seen.add(fp);
561845
+ deduped.push(tc);
561846
+ }
561847
+ if (dropped > 0) {
561848
+ this.emit({
561849
+ type: "status",
561850
+ content: `Response dedupe: dropped ${dropped} exact duplicate tool call(s) before execution (turn ${turn})`,
561851
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
561852
+ });
561853
+ }
561854
+ return deduped;
561855
+ }
561830
561856
  _decodeToolFingerprint(fingerprint) {
561831
561857
  const colonIdx = fingerprint.indexOf(":");
561832
561858
  const toolName = colonIdx > 0 ? fingerprint.slice(0, colonIdx) : fingerprint;
@@ -564687,6 +564713,14 @@ ${memoryLines.join("\n")}`
564687
564713
  if (msg.toolCalls && msg.toolCalls.length > 0) {
564688
564714
  consecutiveTextOnly = 0;
564689
564715
  consecutiveThinkOnly = 0;
564716
+ msg.toolCalls = this._dedupeToolCallsForResponse(msg.toolCalls, turn);
564717
+ if (msg.toolCalls.length === 0) {
564718
+ messages2.push({
564719
+ role: "system",
564720
+ content: "[RESPONSE DEDUPE] All tool calls in the last response were exact duplicates and were dropped. Use the prior results already in context/cache to continue."
564721
+ });
564722
+ continue;
564723
+ }
564690
564724
  const _RESPONSE_CALL_CAPS = {
564691
564725
  small: 2,
564692
564726
  medium: 4,
@@ -567330,6 +567364,14 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
567330
567364
  if (msg.toolCalls && msg.toolCalls.length > 0) {
567331
567365
  consecutiveTextOnly = 0;
567332
567366
  consecutiveThinkOnly = 0;
567367
+ msg.toolCalls = this._dedupeToolCallsForResponse(msg.toolCalls, turn);
567368
+ if (msg.toolCalls.length === 0) {
567369
+ messages2.push({
567370
+ role: "system",
567371
+ content: "[RESPONSE DEDUPE] All tool calls in the last response were exact duplicates and were dropped. Use the prior results already in context/cache to continue."
567372
+ });
567373
+ continue;
567374
+ }
567333
567375
  messages2.push({
567334
567376
  role: "assistant",
567335
567377
  content: msg.content || null,
@@ -572270,6 +572312,54 @@ ${description}`
572270
572312
  releasePoolSlot(poolSuccess);
572271
572313
  }
572272
572314
  }
572315
+ async nativeOllamaChatCompletion(request) {
572316
+ const cleanedMessages = applyMemoryPrefixToMessages(normalizeMessagesForStrictOpenAI(sanitizeHistoryThink(request.messages)), request.memoryPrefix);
572317
+ const requestMessages = injectNoThinkDirective(cleanedMessages);
572318
+ const responseFormat = request.responseFormat ?? request.response_format;
572319
+ const options2 = {
572320
+ temperature: request.temperature,
572321
+ num_predict: request.maxTokens
572322
+ };
572323
+ const reqNumCtx = request.numCtx ?? request.num_ctx;
572324
+ if (Number.isFinite(reqNumCtx) && (reqNumCtx ?? 0) > 0) {
572325
+ options2["num_ctx"] = reqNumCtx;
572326
+ }
572327
+ const body = {
572328
+ model: this.model,
572329
+ messages: requestMessages,
572330
+ stream: false,
572331
+ think: false,
572332
+ options: options2
572333
+ };
572334
+ if (responseFormat !== void 0) {
572335
+ body["format"] = "json";
572336
+ }
572337
+ const effectiveTimeoutMs = Number.isFinite(request.timeoutMs) && request.timeoutMs > 0 ? request.timeoutMs : 0;
572338
+ const timeoutSignal = effectiveTimeoutMs > 0 && typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(effectiveTimeoutMs) : void 0;
572339
+ const fetchOpts = {
572340
+ method: "POST",
572341
+ headers: this.authHeaders(),
572342
+ body: JSON.stringify(body)
572343
+ };
572344
+ if (timeoutSignal)
572345
+ fetchOpts.signal = timeoutSignal;
572346
+ const resp = await fetch(`${this.baseUrl}/api/chat`, fetchOpts);
572347
+ if (!resp.ok) {
572348
+ const text = await resp.text().catch(() => "");
572349
+ throw new Error(`Ollama native HTTP ${resp.status}: ${backendHttpErrorDetail(text)}`);
572350
+ }
572351
+ const data = await resp.json();
572352
+ const message2 = data["message"] ?? {};
572353
+ const content = typeof message2["content"] === "string" ? message2["content"] : "";
572354
+ return {
572355
+ choices: [{ message: { content: content || null } }],
572356
+ usage: buildAgenticUsage({
572357
+ totalTokens: numberFromUnknown2(data["prompt_eval_count"]) ?? 0,
572358
+ promptEvalCount: numberFromUnknown2(data["prompt_eval_count"]),
572359
+ completionTokens: numberFromUnknown2(data["eval_count"])
572360
+ })
572361
+ };
572362
+ }
572273
572363
  /** Anthropic Messages API translation — converts our standard format to/from Anthropic's. */
572274
572364
  async _anthropicChatCompletion(request) {
572275
572365
  const systemMsgs = request.messages.filter((m2) => m2.role === "system");
@@ -641965,7 +642055,7 @@ function renderTelegramSubAgentError(username, error) {
641965
642055
  process.stdout.write(` ${c3.dim("│")} ${c3.magenta("✘")} @${username}: ${c3.dim(preview)}
641966
642056
  `);
641967
642057
  }
641968
- 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_LINK_INTEGRITY_CONTRACT, TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT, TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA, TELEGRAM_INTERACTION_DECISION_REPAIR_SCHEMA, TELEGRAM_CHAT_REPLY_RESPONSE_FORMAT, TELEGRAM_SPACED_URL_RE, TELEGRAM_HTTP_URL_RE, 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_SUB_AGENT_BURST_CONTEXT_LIMIT, TELEGRAM_ADMIN_LIVE_PANEL_PAGES, TELEGRAM_ADMIN_LIVE_MUTATION_TOOLS, 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_DEFAULT_LONG_POLL_TIMEOUT_SECONDS, TELEGRAM_DEFAULT_ROUTER_MODEL_CANDIDATES, TELEGRAM_PUBLIC_TOOL_QUOTAS, TelegramBridge;
642058
+ 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_LINK_INTEGRITY_CONTRACT, TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT, TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA, TELEGRAM_INTERACTION_DECISION_REPAIR_SCHEMA, TELEGRAM_CHAT_REPLY_RESPONSE_FORMAT, TELEGRAM_SPACED_URL_RE, TELEGRAM_HTTP_URL_RE, 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_SUB_AGENT_BURST_CONTEXT_LIMIT, TELEGRAM_ADMIN_LIVE_PANEL_PAGES, TELEGRAM_ADMIN_LIVE_MUTATION_TOOLS, 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_DEFAULT_LONG_POLL_TIMEOUT_SECONDS, TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B, TELEGRAM_PUBLIC_TOOL_QUOTAS, TelegramBridge;
641969
642059
  var init_telegram_bridge = __esm({
641970
642060
  "packages/cli/src/tui/telegram-bridge.ts"() {
641971
642061
  "use strict";
@@ -642428,20 +642518,7 @@ Telegram link integrity contract:
642428
642518
  TELEGRAM_CHANNEL_DMN_MIN_MESSAGES = 4;
642429
642519
  TELEGRAM_ALLOWED_UPDATES = ["message", "guest_message", "callback_query", "poll", "message_reaction", "message_reaction_count"];
642430
642520
  TELEGRAM_DEFAULT_LONG_POLL_TIMEOUT_SECONDS = 50;
642431
- TELEGRAM_DEFAULT_ROUTER_MODEL_CANDIDATES = [
642432
- "qwen2.5:3b",
642433
- "qwen2.5:7b",
642434
- "llama3.2:1b",
642435
- "llama3.2:3b",
642436
- "gemma3:1b",
642437
- "gemma3:4b",
642438
- "phi3:mini",
642439
- "phi4-mini:latest",
642440
- "qwen3:0.6b",
642441
- "qwen3:1.7b",
642442
- "qwen3:4b",
642443
- "qwen3:8b"
642444
- ];
642521
+ TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B = 8;
642445
642522
  TELEGRAM_PUBLIC_TOOL_QUOTAS = {
642446
642523
  web: { limit: 20, windowMs: 60 * 6e4 },
642447
642524
  media: { limit: 30, windowMs: 60 * 6e4 },
@@ -647277,8 +647354,13 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`,
647277
647354
  const suppressed = telegramThinkSuppressedRequest(request);
647278
647355
  const requestTimeoutMs = Number.isFinite(suppressed.timeoutMs) && (suppressed.timeoutMs ?? 0) > 0 ? suppressed.timeoutMs : void 0;
647279
647356
  const jsonStartMs = Date.now();
647357
+ const nativeOllamaRouter = diagnostics?.backendType === "ollama" && typeof backend.nativeOllamaChatCompletion === "function";
647280
647358
  try {
647281
- jsonModeResult = await this.telegramObservableInference(
647359
+ jsonModeResult = nativeOllamaRouter ? await backend.nativeOllamaChatCompletion({
647360
+ ...suppressed,
647361
+ responseFormat: TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT,
647362
+ disableEmptyContentRecovery: true
647363
+ }) : await this.telegramObservableInference(
647282
647364
  backend,
647283
647365
  {
647284
647366
  ...suppressed,
@@ -647338,7 +647420,7 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`,
647338
647420
  }
647339
647421
  const plainStartMs = Date.now();
647340
647422
  try {
647341
- const plainResult = await this.telegramObservableInference(
647423
+ const plainResult = nativeOllamaRouter ? await backend.nativeOllamaChatCompletion(suppressed) : await this.telegramObservableInference(
647342
647424
  backend,
647343
647425
  suppressed,
647344
647426
  inferenceKind,
@@ -648028,11 +648110,11 @@ ${retryText}`,
648028
648110
  }
648029
648111
  telegramRouterAutoModelEnabled() {
648030
648112
  const raw = (process.env["OMNIUS_TG_ROUTER_AUTO_MODEL"] ?? "").trim().toLowerCase();
648031
- return raw !== "0" && raw !== "false" && raw !== "off";
648113
+ return raw === "1" || raw === "true" || raw === "on";
648032
648114
  }
648033
648115
  telegramRouterCandidateModels() {
648034
648116
  const raw = (process.env["OMNIUS_TG_ROUTER_MODEL_CANDIDATES"] ?? "").trim();
648035
- const candidates = raw ? raw.split(/[,\s]+/).map((part) => part.trim()).filter(Boolean) : TELEGRAM_DEFAULT_ROUTER_MODEL_CANDIDATES;
648117
+ const candidates = raw ? raw.split(/[,\s]+/).map((part) => part.trim()).filter(Boolean) : [];
648036
648118
  return Array.from(new Set(candidates));
648037
648119
  }
648038
648120
  telegramRouterAllowThinkHeavyAutoModels() {
@@ -648042,16 +648124,10 @@ ${retryText}`,
648042
648124
  telegramRouterModelLooksThinkHeavy(name10) {
648043
648125
  return /\b(?:qwen3|qwq|deepseek-r1|r1-|reasoning)\b/i.test(name10);
648044
648126
  }
648045
- orderTelegramRouterCandidates(candidates) {
648046
- if (this.telegramRouterAllowThinkHeavyAutoModels()) return candidates;
648047
- const stable = candidates.filter((candidate) => !this.telegramRouterModelLooksThinkHeavy(candidate));
648048
- const thinkHeavy = candidates.filter((candidate) => this.telegramRouterModelLooksThinkHeavy(candidate));
648049
- return [...stable, ...thinkHeavy];
648050
- }
648051
648127
  normalizeOllamaModelNameForMatch(name10) {
648052
648128
  return name10.trim().toLowerCase().replace(/:latest$/, "");
648053
648129
  }
648054
- async fetchOllamaInstalledModelNames(baseUrl) {
648130
+ async fetchOllamaInstalledModels(baseUrl) {
648055
648131
  const url = `${baseUrl.replace(/\/+$/, "")}/api/tags`;
648056
648132
  const timeoutFn = AbortSignal.timeout;
648057
648133
  const res = await fetch(url, {
@@ -648059,7 +648135,43 @@ ${retryText}`,
648059
648135
  });
648060
648136
  if (!res.ok) throw new Error(`ollama /api/tags returned HTTP ${res.status}`);
648061
648137
  const data = await res.json();
648062
- return Array.isArray(data.models) ? data.models.map((model) => typeof model.name === "string" ? model.name : "").filter(Boolean) : [];
648138
+ return Array.isArray(data.models) ? data.models.map((model) => ({
648139
+ name: typeof model.name === "string" ? model.name : "",
648140
+ sizeBytes: typeof model.size === "number" ? model.size : void 0,
648141
+ parameterSize: typeof model.details?.parameter_size === "string" ? model.details.parameter_size : void 0
648142
+ })).filter((model) => Boolean(model.name)) : [];
648143
+ }
648144
+ telegramModelParameterBillions(model) {
648145
+ const haystack = `${model.name} ${model.parameterSize ?? ""}`.toLowerCase();
648146
+ const billion = haystack.match(/(\d+(?:\.\d+)?)\s*(?:b|bn)\b/);
648147
+ if (billion) return Number(billion[1]);
648148
+ const million = haystack.match(/(\d+(?:\.\d+)?)\s*m\b/);
648149
+ if (million) return Number(million[1]) / 1e3;
648150
+ return null;
648151
+ }
648152
+ scoreTelegramInstalledRouterModel(model) {
648153
+ const name10 = model.name.toLowerCase();
648154
+ if (/(?:embed|embedding|nomic|bge|e5-|clip|rerank|moondream|llava|vision|vl\b|minicpm|whisper|tts|sdxl|diffusion)/i.test(name10)) {
648155
+ return Number.NEGATIVE_INFINITY;
648156
+ }
648157
+ const paramsB = this.telegramModelParameterBillions(model);
648158
+ if (paramsB !== null && paramsB < TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B) {
648159
+ return Number.NEGATIVE_INFINITY;
648160
+ }
648161
+ if (paramsB === null && (model.sizeBytes ?? 0) < 5e9) {
648162
+ return Number.NEGATIVE_INFINITY;
648163
+ }
648164
+ let score = 0;
648165
+ if (paramsB !== null) score += paramsB * 10;
648166
+ else score += Math.min(80, (model.sizeBytes ?? 0) / 1e9);
648167
+ if (/qwen|huihui|qwq/i.test(name10)) score += 80;
648168
+ else if (/deepseek|nemotron|llama|mistral|mixtral|command-r|devstral/i.test(name10)) score += 50;
648169
+ else if (/gemma/i.test(name10)) score += 20;
648170
+ if (/:latest$/i.test(model.name)) score += 1;
648171
+ if (this.telegramRouterModelLooksThinkHeavy(model.name) && !this.telegramRouterAllowThinkHeavyAutoModels()) {
648172
+ score -= 15;
648173
+ }
648174
+ return score;
648063
648175
  }
648064
648176
  async resolveTelegramRouterBackend(config) {
648065
648177
  const explicit = (process.env["OMNIUS_TG_ROUTER_MODEL"] ?? "").trim();
@@ -648071,17 +648183,20 @@ ${retryText}`,
648071
648183
  detail: "OMNIUS_TG_ROUTER_MODEL"
648072
648184
  };
648073
648185
  }
648074
- if (config.backendType !== "ollama" || !this.telegramRouterAutoModelEnabled()) {
648186
+ if (config.backendType !== "ollama") {
648075
648187
  return {
648076
648188
  backend: new OllamaAgenticBackend(config.backendUrl, config.model, config.apiKey),
648077
648189
  model: config.model,
648078
648190
  source: "main"
648079
648191
  };
648080
648192
  }
648081
- const candidates = this.orderTelegramRouterCandidates(this.telegramRouterCandidateModels());
648193
+ const autoModelEnabled = this.telegramRouterAutoModelEnabled();
648194
+ const candidateFilter = this.telegramRouterCandidateModels();
648195
+ const candidates = new Set(candidateFilter.map((candidate) => this.normalizeOllamaModelNameForMatch(candidate)));
648082
648196
  const cacheKey = `${config.backendUrl}
648083
648197
  ${config.model}
648084
- ${candidates.join(",")}`;
648198
+ auto=${autoModelEnabled ? "1" : "0"}
648199
+ ${candidateFilter.join(",")}`;
648085
648200
  const now = Date.now();
648086
648201
  if (this.telegramRouterModelCache && this.telegramRouterModelCache.cacheKey === cacheKey && now - this.telegramRouterModelCache.atMs < 6e4) {
648087
648202
  const cached = this.telegramRouterModelCache;
@@ -648092,30 +648207,65 @@ ${candidates.join(",")}`;
648092
648207
  detail: cached.detail
648093
648208
  };
648094
648209
  }
648210
+ if (!autoModelEnabled) {
648211
+ const detail2 = "Telegram router auto-model selection is disabled by default; using main model";
648212
+ this.telegramRouterModelCache = {
648213
+ cacheKey,
648214
+ atMs: now,
648215
+ model: config.model,
648216
+ source: "main",
648217
+ detail: detail2
648218
+ };
648219
+ return {
648220
+ backend: new OllamaAgenticBackend(config.backendUrl, config.model, config.apiKey),
648221
+ model: config.model,
648222
+ source: "main",
648223
+ detail: detail2
648224
+ };
648225
+ }
648095
648226
  try {
648096
- const installed = await this.fetchOllamaInstalledModelNames(config.backendUrl);
648227
+ const installed = await this.fetchOllamaInstalledModels(config.backendUrl);
648097
648228
  const installedByNormalized = /* @__PURE__ */ new Map();
648098
- for (const name10 of installed) {
648099
- installedByNormalized.set(this.normalizeOllamaModelNameForMatch(name10), name10);
648229
+ for (const model of installed) {
648230
+ installedByNormalized.set(this.normalizeOllamaModelNameForMatch(model.name), model);
648100
648231
  }
648101
- for (const candidate of candidates) {
648102
- const selected = installedByNormalized.get(this.normalizeOllamaModelNameForMatch(candidate));
648103
- if (!selected) continue;
648232
+ const installedMain = installedByNormalized.get(this.normalizeOllamaModelNameForMatch(config.model));
648233
+ if (installedMain) {
648104
648234
  const resolved = {
648105
648235
  cacheKey,
648106
648236
  atMs: now,
648107
- model: selected,
648108
- source: "auto-small",
648109
- detail: "selected first installed Telegram router candidate from Ollama /api/tags; think-heavy models are tried last unless OMNIUS_TG_ROUTER_ALLOW_THINK_MODELS=1"
648237
+ model: installedMain.name,
648238
+ source: "main",
648239
+ detail: "main Telegram router model is installed in Ollama /api/tags; using main model by policy"
648110
648240
  };
648111
648241
  this.telegramRouterModelCache = resolved;
648112
648242
  return {
648113
- backend: new OllamaAgenticBackend(config.backendUrl, selected, config.apiKey),
648114
- model: selected,
648115
- source: "auto-small",
648243
+ backend: new OllamaAgenticBackend(config.backendUrl, installedMain.name, config.apiKey),
648244
+ model: installedMain.name,
648245
+ source: "main",
648116
648246
  detail: resolved.detail
648117
648247
  };
648118
648248
  }
648249
+ if (autoModelEnabled) {
648250
+ const pool3 = candidateFilter.length > 0 ? installed.filter((model) => candidates.has(this.normalizeOllamaModelNameForMatch(model.name))) : installed;
648251
+ const selected = pool3.map((model) => ({ model, score: this.scoreTelegramInstalledRouterModel(model) })).filter((entry) => Number.isFinite(entry.score)).sort((a2, b) => b.score - a2.score)[0]?.model;
648252
+ if (selected) {
648253
+ const resolved = {
648254
+ cacheKey,
648255
+ atMs: now,
648256
+ model: selected.name,
648257
+ source: "auto-installed",
648258
+ detail: `main Telegram router model ${JSON.stringify(config.model)} was not found in Ollama /api/tags; selected best installed capable router model dynamically (minimum ${TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B}B, excludes embeddings/vision/tiny models)`
648259
+ };
648260
+ this.telegramRouterModelCache = resolved;
648261
+ return {
648262
+ backend: new OllamaAgenticBackend(config.backendUrl, selected.name, config.apiKey),
648263
+ model: selected.name,
648264
+ source: "auto-installed",
648265
+ detail: resolved.detail
648266
+ };
648267
+ }
648268
+ }
648119
648269
  } catch (err) {
648120
648270
  const detail2 = `router model auto-detect failed: ${err instanceof Error ? err.message : String(err)}`;
648121
648271
  this.telegramRouterModelCache = {
@@ -648132,7 +648282,7 @@ ${candidates.join(",")}`;
648132
648282
  detail: detail2
648133
648283
  };
648134
648284
  }
648135
- const detail = "no configured small router model was installed; using main model";
648285
+ const detail = `no installed capable Telegram router model met the dynamic minimum (${TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B}B); using main model`;
648136
648286
  this.telegramRouterModelCache = {
648137
648287
  cacheKey,
648138
648288
  atMs: now,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.209",
3
+ "version": "1.0.211",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.209",
9
+ "version": "1.0.211",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -2310,9 +2310,9 @@
2310
2310
  }
2311
2311
  },
2312
2312
  "node_modules/bare-path": {
2313
- "version": "3.0.0",
2314
- "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
2315
- "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
2313
+ "version": "3.0.1",
2314
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz",
2315
+ "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==",
2316
2316
  "license": "Apache-2.0",
2317
2317
  "optional": true,
2318
2318
  "dependencies": {
@@ -6886,9 +6886,9 @@
6886
6886
  }
6887
6887
  },
6888
6888
  "node_modules/undici": {
6889
- "version": "7.26.0",
6890
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.26.0.tgz",
6891
- "integrity": "sha512-3O9Tf67pGhgOv9jM35AbhkXAKi13f3oy3aE4CSgr+TckGeY+/iu97ZXN+J7DpHPzLbVApFd1IFhcnBjREYXYcg==",
6889
+ "version": "7.27.0",
6890
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.0.tgz",
6891
+ "integrity": "sha512-+t2Z/GwkZQDtu00813aP66ygViGtPHKhhoFZpQKpKrE+9jIgES+Zw+mFNaDWOVRKiuJjuqKHzD3B1sfGg8+ZOQ==",
6892
6892
  "license": "MIT",
6893
6893
  "engines": {
6894
6894
  "node": ">=20.18.1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.209",
3
+ "version": "1.0.211",
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",