omnius 1.0.76 → 1.0.78

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
@@ -551418,6 +551418,7 @@ ${description}`
551418
551418
  if (effectiveThink === true && (effectiveMaxTokens ?? 0) < 4096) {
551419
551419
  effectiveMaxTokens = 4096;
551420
551420
  }
551421
+ const responseFormat = request.responseFormat ?? request.response_format;
551421
551422
  const body = {
551422
551423
  model: this.model,
551423
551424
  messages: cleanedMessages,
@@ -551426,6 +551427,9 @@ ${description}`
551426
551427
  max_tokens: effectiveMaxTokens,
551427
551428
  think: effectiveThink
551428
551429
  };
551430
+ if (responseFormat !== void 0) {
551431
+ body["response_format"] = responseFormat;
551432
+ }
551429
551433
  const poolSlot = shouldUseOllamaPoolForBaseUrl(this.baseUrl) ? await getOllamaPool({ baseInstanceUrl: this.baseUrl }).acquire({
551430
551434
  model: this.model
551431
551435
  }) : null;
@@ -551463,6 +551467,9 @@ ${description}`
551463
551467
  max_tokens: request.maxTokens,
551464
551468
  think: false
551465
551469
  };
551470
+ if (responseFormat !== void 0) {
551471
+ retryBody["response_format"] = responseFormat;
551472
+ }
551466
551473
  try {
551467
551474
  const retryOpts = {
551468
551475
  method: "POST",
@@ -610245,44 +610252,157 @@ function telegramDecisionNote(parsed, keys, nestedKeys = ["internal_notes", "int
610245
610252
  }
610246
610253
  return void 0;
610247
610254
  }
610255
+ function uniqueTelegramJsonCandidates(candidates) {
610256
+ const seen = /* @__PURE__ */ new Set();
610257
+ const unique = [];
610258
+ for (const candidate of candidates) {
610259
+ const clean5 = candidate.trim();
610260
+ if (!clean5 || seen.has(clean5)) continue;
610261
+ seen.add(clean5);
610262
+ unique.push(clean5);
610263
+ }
610264
+ return unique;
610265
+ }
610266
+ function extractBalancedTelegramJsonObjects(text) {
610267
+ const objects = [];
610268
+ let start2 = -1;
610269
+ let depth = 0;
610270
+ let inString = false;
610271
+ let escaped = false;
610272
+ for (let idx = 0; idx < text.length; idx++) {
610273
+ const ch = text[idx];
610274
+ if (inString) {
610275
+ if (escaped) {
610276
+ escaped = false;
610277
+ } else if (ch === "\\") {
610278
+ escaped = true;
610279
+ } else if (ch === '"') {
610280
+ inString = false;
610281
+ }
610282
+ continue;
610283
+ }
610284
+ if (ch === '"') {
610285
+ inString = true;
610286
+ continue;
610287
+ }
610288
+ if (ch === "{") {
610289
+ if (depth === 0) start2 = idx;
610290
+ depth += 1;
610291
+ continue;
610292
+ }
610293
+ if (ch === "}" && depth > 0) {
610294
+ depth -= 1;
610295
+ if (depth === 0 && start2 >= 0) {
610296
+ objects.push(text.slice(start2, idx + 1));
610297
+ start2 = -1;
610298
+ }
610299
+ }
610300
+ }
610301
+ return objects;
610302
+ }
610303
+ function telegramDecisionJsonCandidates(text) {
610304
+ const cleaned = stripTelegramHiddenThinking(text).trim();
610305
+ if (!cleaned) return [];
610306
+ const candidates = [];
610307
+ const fenced = cleaned.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi);
610308
+ for (const match of fenced) {
610309
+ if (match[1]) candidates.push(match[1]);
610310
+ }
610311
+ candidates.push(cleaned);
610312
+ candidates.push(cleaned.replace(/```(?:json)?/gi, "").replace(/```/g, "").trim());
610313
+ candidates.push(cleaned.replace(/^\s*(?:json|decision|router decision)\s*:?\s*/i, "").trim());
610314
+ const expanded = [];
610315
+ for (const candidate of candidates) {
610316
+ if (!candidate.trim()) continue;
610317
+ expanded.push(candidate);
610318
+ expanded.push(...extractBalancedTelegramJsonObjects(candidate));
610319
+ }
610320
+ return uniqueTelegramJsonCandidates(expanded);
610321
+ }
610322
+ function telegramDecisionOutputHasDanglingJson(text) {
610323
+ const cleaned = stripTelegramHiddenThinking(text).trim();
610324
+ if (!cleaned || extractBalancedTelegramJsonObjects(cleaned).length > 0) return false;
610325
+ let depth = 0;
610326
+ let inString = false;
610327
+ let escaped = false;
610328
+ for (let idx = 0; idx < cleaned.length; idx++) {
610329
+ const ch = cleaned[idx];
610330
+ if (inString) {
610331
+ if (escaped) {
610332
+ escaped = false;
610333
+ } else if (ch === "\\") {
610334
+ escaped = true;
610335
+ } else if (ch === '"') {
610336
+ inString = false;
610337
+ }
610338
+ continue;
610339
+ }
610340
+ if (ch === '"') {
610341
+ inString = true;
610342
+ continue;
610343
+ }
610344
+ if (ch === "{") depth += 1;
610345
+ if (ch === "}" && depth > 0) depth -= 1;
610346
+ }
610347
+ return depth > 0;
610348
+ }
610349
+ function telegramRouterRawPreview(text, maxLength = 320) {
610350
+ const clean5 = stripTelegramHiddenThinking(text).replace(/\s+/g, " ").trim();
610351
+ if (!clean5) return void 0;
610352
+ return clean5.length > maxLength ? `${clean5.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...` : clean5;
610353
+ }
610354
+ function telegramDecisionRecoverableFlag(text) {
610355
+ for (const jsonText of telegramDecisionJsonCandidates(text)) {
610356
+ try {
610357
+ const parsed = JSON.parse(jsonText);
610358
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
610359
+ const recoverable = parsed["recoverable"];
610360
+ if (typeof recoverable === "boolean") return recoverable;
610361
+ } catch {
610362
+ continue;
610363
+ }
610364
+ }
610365
+ return void 0;
610366
+ }
610248
610367
  function parseTelegramInteractionDecision(text, forcedRoute, options2 = {}) {
610249
- const cleaned = stripTelegramHiddenThinking(text).replace(/```(?:json)?/gi, "").replace(/```/g, "").trim();
610250
- const jsonText = cleaned.startsWith("{") ? cleaned : cleaned.match(/\{[\s\S]*\}/)?.[0] ?? "";
610251
- if (!jsonText) return null;
610252
- try {
610253
- const parsed = JSON.parse(jsonText);
610254
- const parsedRoute = parsed["route"] === "chat" || parsed["route"] === "action" ? parsed["route"] : null;
610255
- const route = forcedRoute ?? parsedRoute;
610256
- if (!route) return null;
610257
- const shouldReplyRaw = parsed["should_reply"] ?? parsed["shouldReply"];
610258
- const shouldReply = typeof shouldReplyRaw === "boolean" ? shouldReplyRaw : options2.defaultShouldReply ?? true;
610259
- const confidenceRaw = Number(parsed["confidence"]);
610260
- const confidence2 = Number.isFinite(confidenceRaw) ? Math.max(0, Math.min(1, confidenceRaw)) : 0;
610261
- const reason = String(parsed["reason"] ?? "live inference decision").slice(0, 240);
610262
- const attentionDeltaRaw = Number(parsed["attention_delta"] ?? parsed["attentionDelta"]);
610263
- const attentionScoreRaw = Number(parsed["attention_score"] ?? parsed["attentionScore"]);
610264
- const nextMessagesRaw = Number(parsed["next_check_after_messages"] ?? parsed["nextCheckAfterMessages"]);
610265
- const nextMsRaw = Number(parsed["next_check_after_ms"] ?? parsed["nextCheckAfterMs"]);
610266
- return {
610267
- route,
610268
- shouldReply,
610269
- confidence: confidence2,
610270
- reason,
610271
- source: forcedRoute ? "forced-mode" : "live-inference",
610272
- raw: text,
610273
- attentionState: parseStimulationPhase(parsed["attention_state"] ?? parsed["attentionState"]),
610274
- attentionDelta: Number.isFinite(attentionDeltaRaw) ? Math.max(-1, Math.min(1, attentionDeltaRaw)) : void 0,
610275
- attentionScore: Number.isFinite(attentionScoreRaw) ? Math.max(0, Math.min(1, attentionScoreRaw)) : void 0,
610276
- nextCheckAfterMessages: Number.isFinite(nextMessagesRaw) ? Math.max(1, Math.floor(nextMessagesRaw)) : void 0,
610277
- nextCheckAfterMs: Number.isFinite(nextMsRaw) ? Math.max(0, Math.floor(nextMsRaw)) : void 0,
610278
- silentDisposition: telegramDecisionNote(parsed, ["silent_disposition", "silentDisposition", "disposition"]),
610279
- mentalNote: telegramDecisionNote(parsed, ["mental_note", "mentalNote", "observation", "insight"]),
610280
- memoryNote: telegramDecisionNote(parsed, ["memory_note", "memoryNote", "memory"]),
610281
- relationshipNote: telegramDecisionNote(parsed, ["relationship_note", "relationshipNote", "relationship"])
610282
- };
610283
- } catch {
610284
- return null;
610368
+ for (const jsonText of telegramDecisionJsonCandidates(text)) {
610369
+ try {
610370
+ const parsed = JSON.parse(jsonText);
610371
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
610372
+ const parsedRoute = parsed["route"] === "chat" || parsed["route"] === "action" ? parsed["route"] : null;
610373
+ const route = forcedRoute ?? parsedRoute;
610374
+ if (!route) continue;
610375
+ const shouldReplyRaw = parsed["should_reply"] ?? parsed["shouldReply"];
610376
+ const shouldReply = typeof shouldReplyRaw === "boolean" ? shouldReplyRaw : options2.defaultShouldReply ?? true;
610377
+ const confidenceRaw = Number(parsed["confidence"]);
610378
+ const confidence2 = Number.isFinite(confidenceRaw) ? Math.max(0, Math.min(1, confidenceRaw)) : 0;
610379
+ const reason = String(parsed["reason"] ?? "live inference decision").slice(0, 240);
610380
+ const attentionDeltaRaw = Number(parsed["attention_delta"] ?? parsed["attentionDelta"]);
610381
+ const attentionScoreRaw = Number(parsed["attention_score"] ?? parsed["attentionScore"]);
610382
+ const nextMessagesRaw = Number(parsed["next_check_after_messages"] ?? parsed["nextCheckAfterMessages"]);
610383
+ const nextMsRaw = Number(parsed["next_check_after_ms"] ?? parsed["nextCheckAfterMs"]);
610384
+ return {
610385
+ route,
610386
+ shouldReply,
610387
+ confidence: confidence2,
610388
+ reason,
610389
+ source: forcedRoute ? "forced-mode" : "live-inference",
610390
+ raw: text,
610391
+ attentionState: parseStimulationPhase(parsed["attention_state"] ?? parsed["attentionState"]),
610392
+ attentionDelta: Number.isFinite(attentionDeltaRaw) ? Math.max(-1, Math.min(1, attentionDeltaRaw)) : void 0,
610393
+ attentionScore: Number.isFinite(attentionScoreRaw) ? Math.max(0, Math.min(1, attentionScoreRaw)) : void 0,
610394
+ nextCheckAfterMessages: Number.isFinite(nextMessagesRaw) ? Math.max(1, Math.floor(nextMessagesRaw)) : void 0,
610395
+ nextCheckAfterMs: Number.isFinite(nextMsRaw) ? Math.max(0, Math.floor(nextMsRaw)) : void 0,
610396
+ silentDisposition: telegramDecisionNote(parsed, ["silent_disposition", "silentDisposition", "disposition"]),
610397
+ mentalNote: telegramDecisionNote(parsed, ["mental_note", "mentalNote", "observation", "insight"]),
610398
+ memoryNote: telegramDecisionNote(parsed, ["memory_note", "memoryNote", "memory"]),
610399
+ relationshipNote: telegramDecisionNote(parsed, ["relationship_note", "relationshipNote", "relationship"])
610400
+ };
610401
+ } catch {
610402
+ continue;
610403
+ }
610285
610404
  }
610405
+ return null;
610286
610406
  }
610287
610407
  function parseTelegramTimeRangeQuery(query, now = /* @__PURE__ */ new Date()) {
610288
610408
  const original = String(query || "");
@@ -611640,7 +611760,7 @@ function renderTelegramSubAgentError(username, error) {
611640
611760
  process.stdout.write(` ${c3.dim("│")} ${c3.red("✘")} @${username}: ${c3.dim(preview)}
611641
611761
  `);
611642
611762
  }
611643
- 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_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_COMMANDS, 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;
611763
+ 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_COMMANDS, 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;
611644
611764
  var init_telegram_bridge = __esm({
611645
611765
  "packages/cli/src/tui/telegram-bridge.ts"() {
611646
611766
  "use strict";
@@ -611897,6 +612017,9 @@ External acquisition contract:
611897
612017
  - The browser tool is for interactive web work; it does not save arbitrary rendered files to disk. For file acquisition, use the download/file tool and verify content-type + size before reporting success.
611898
612018
  - Report the exact blocker concisely and offer lawful alternatives (library hold, official store, summary/discussion if the user supplies an authorized copy).
611899
612019
  `.trim();
612020
+ TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT = {
612021
+ type: "json_object"
612022
+ };
611900
612023
  TELEGRAM_STUCK_SELF_TALK_PREFIXES = [
611901
612024
  /^i'?ve been stuck for\b/i,
611902
612025
  /^i am (still |currently )?stuck\b/i,
@@ -615233,6 +615356,117 @@ ${lines.join("\n")}`);
615233
615356
  nextAnalysisAfterMs: decision.nextCheckAfterMs
615234
615357
  });
615235
615358
  }
615359
+ async telegramRouterJsonCompletion(backend, request) {
615360
+ try {
615361
+ return await backend.chatCompletion({
615362
+ ...request,
615363
+ responseFormat: TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT
615364
+ });
615365
+ } catch {
615366
+ return backend.chatCompletion(request);
615367
+ }
615368
+ }
615369
+ async repairTelegramInteractionDecision(backend, rawOutput, forcedRoute, timeoutMs) {
615370
+ const rawPreview = telegramRouterRawPreview(rawOutput, 4e3);
615371
+ if (!rawPreview || telegramDecisionOutputHasDanglingJson(rawOutput)) return null;
615372
+ const routeInstruction = forcedRoute ? `The route is operator-forced and must be "${forcedRoute}".` : `Preserve the original route if present; otherwise choose chat or action only if the original output clearly implies one.`;
615373
+ const prompt = [
615374
+ `Repair this Telegram attention-router output into strict JSON.`,
615375
+ `Do not make a new social decision from the Telegram message. Only preserve the decision already present in the router output.`,
615376
+ `If the original output does not contain a recoverable route and should_reply decision, return recoverable=false with should_reply=false and confidence=0.`,
615377
+ routeInstruction,
615378
+ ``,
615379
+ `Return JSON only with this schema:`,
615380
+ `{"recoverable":true|false,"route":"chat"|"action","should_reply":true|false,"confidence":0.0-1.0,"reason":"short reason","attention_state":"idle"|"observing"|"engaged"|"cooldown","attention_delta":-1.0..1.0,"next_check_after_messages":1..12,"silent_disposition":"short outcome-level disposition","mental_note":"short outcome-level observation","memory_note":"short memory/summary update","relationship_note":"short relationship/thread note"}`,
615381
+ ``,
615382
+ `Original router output:`,
615383
+ rawPreview
615384
+ ].join("\n");
615385
+ try {
615386
+ const result = await this.telegramRouterJsonCompletion(backend, {
615387
+ messages: [
615388
+ {
615389
+ role: "system",
615390
+ content: "You repair a Telegram router response into strict JSON without changing the underlying decision."
615391
+ },
615392
+ { role: "user", content: prompt }
615393
+ ],
615394
+ tools: [],
615395
+ temperature: 0,
615396
+ maxTokens: 500,
615397
+ timeoutMs: Math.min(Math.max(timeoutMs, 3e3), 8e3),
615398
+ think: false
615399
+ });
615400
+ const repairedText = result.choices[0]?.message?.content ?? "";
615401
+ if (telegramDecisionRecoverableFlag(repairedText) === false) return null;
615402
+ const parsed = parseTelegramInteractionDecision(repairedText, forcedRoute, {
615403
+ defaultShouldReply: false
615404
+ });
615405
+ if (!parsed) return null;
615406
+ return {
615407
+ ...parsed,
615408
+ reason: `recovered router decision: ${parsed.reason}`.slice(0, 240),
615409
+ raw: `${rawOutput}
615410
+
615411
+ [repaired router decision]
615412
+ ${repairedText}`,
615413
+ mentalNote: parsed.mentalNote ?? "router decision recovered from non-JSON model output",
615414
+ memoryNote: parsed.memoryNote ?? "router repair preserved the model-derived attention decision"
615415
+ };
615416
+ } catch {
615417
+ return null;
615418
+ }
615419
+ }
615420
+ async retryTelegramInteractionDecisionStrict(backend, userPrompt, rawOutput, forcedRoute, timeoutMs) {
615421
+ const invalidPreview = telegramRouterRawPreview(rawOutput, 1200) ?? "(empty assistant content)";
615422
+ const routeInstruction = forcedRoute ? `The operator selected Telegram mode "${forcedRoute}". The route field must be "${forcedRoute}", but should_reply must still be inferred from context.` : `Infer route live from context.`;
615423
+ const retryPrompt = [
615424
+ `The previous Telegram attention-router response was not usable JSON.`,
615425
+ `Make a fresh model-derived attention decision from the full context below. Do not use hard-coded mention or keyword triggers.`,
615426
+ `Return exactly one JSON object and no prose.`,
615427
+ routeInstruction,
615428
+ ``,
615429
+ `Required schema: {"route":"chat"|"action","should_reply":true|false,"confidence":0.0-1.0,"reason":"short reason","attention_state":"idle"|"observing"|"engaged"|"cooldown","attention_delta":-1.0..1.0,"next_check_after_messages":1..12,"silent_disposition":"short outcome-level disposition","mental_note":"short outcome-level observation","memory_note":"short memory/summary update","relationship_note":"short relationship/thread note"}`,
615430
+ ``,
615431
+ `Invalid previous output, for diagnostics only:`,
615432
+ invalidPreview,
615433
+ ``,
615434
+ `Full router context:`,
615435
+ userPrompt
615436
+ ].join("\n");
615437
+ try {
615438
+ const result = await this.telegramRouterJsonCompletion(backend, {
615439
+ messages: [
615440
+ {
615441
+ role: "system",
615442
+ content: "You are a strict JSON Telegram attention router. Output one valid JSON object only."
615443
+ },
615444
+ { role: "user", content: retryPrompt }
615445
+ ],
615446
+ tools: [],
615447
+ temperature: 0,
615448
+ maxTokens: 1200,
615449
+ timeoutMs: Math.min(Math.max(timeoutMs, 5e3), 15e3),
615450
+ think: false
615451
+ });
615452
+ const retryText = result.choices[0]?.message?.content ?? "";
615453
+ const parsed = parseTelegramInteractionDecision(retryText, forcedRoute, {
615454
+ defaultShouldReply: false
615455
+ });
615456
+ if (!parsed) return null;
615457
+ return {
615458
+ ...parsed,
615459
+ reason: `strict router retry: ${parsed.reason}`.slice(0, 240),
615460
+ raw: `${rawOutput}
615461
+
615462
+ [strict router retry]
615463
+ ${retryText}`,
615464
+ mentalNote: parsed.mentalNote ?? "strict router retry produced a valid attention decision"
615465
+ };
615466
+ } catch {
615467
+ return null;
615468
+ }
615469
+ }
615236
615470
  async inferTelegramInteractionDecision(msg, toolContext) {
615237
615471
  const config = this.agentConfig;
615238
615472
  const forcedRoute = this.interactionMode === "chat" || this.interactionMode === "action" ? this.interactionMode : null;
@@ -615316,7 +615550,7 @@ ${stimulationProbe.context}`,
615316
615550
  ${this.quoteTelegramContextBlock(msg.text, 1200)}`
615317
615551
  ].filter(Boolean).join("\n");
615318
615552
  try {
615319
- const result = await backend.chatCompletion({
615553
+ const result = await this.telegramRouterJsonCompletion(backend, {
615320
615554
  messages: [
615321
615555
  {
615322
615556
  role: "system",
@@ -615338,14 +615572,37 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
615338
615572
  this.applyTelegramStimulationDecision(sessionKey, parsed);
615339
615573
  return parsed;
615340
615574
  }
615575
+ const repaired = await this.repairTelegramInteractionDecision(
615576
+ backend,
615577
+ text,
615578
+ forcedRoute,
615579
+ config.timeoutMs ?? 3e4
615580
+ );
615581
+ if (repaired) {
615582
+ this.applyTelegramStimulationDecision(sessionKey, repaired);
615583
+ return repaired;
615584
+ }
615585
+ const strictRetry = await this.retryTelegramInteractionDecisionStrict(
615586
+ backend,
615587
+ userPrompt,
615588
+ text,
615589
+ forcedRoute,
615590
+ config.timeoutMs ?? 3e4
615591
+ );
615592
+ if (strictRetry) {
615593
+ this.applyTelegramStimulationDecision(sessionKey, strictRetry);
615594
+ return strictRetry;
615595
+ }
615596
+ const invalidRouterPreview = telegramRouterRawPreview(text);
615341
615597
  const fallback2 = {
615342
615598
  route: forcedRoute ?? (isGroup ? "action" : "chat"),
615343
615599
  shouldReply: false,
615344
615600
  confidence: 0,
615345
- reason: "router output was not valid decision JSON; no model-derived reply decision",
615601
+ reason: "router output was not valid decision JSON after repair/retry; no model-derived reply decision",
615346
615602
  source: "inference-unavailable",
615347
615603
  silentDisposition: "retained as context without replying because the router decision could not be parsed",
615348
- mentalNote: "router produced an invalid attention decision payload",
615604
+ mentalNote: invalidRouterPreview ? "router produced an invalid attention decision payload; repair and strict retry did not recover it" : "router produced an empty attention decision payload; strict retry did not recover it",
615605
+ memoryNote: invalidRouterPreview ? `invalid router output preview: ${invalidRouterPreview}` : void 0,
615349
615606
  raw: text
615350
615607
  };
615351
615608
  this.applyTelegramStimulationDecision(sessionKey, fallback2);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.76",
3
+ "version": "1.0.78",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.76",
9
+ "version": "1.0.78",
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.76",
3
+ "version": "1.0.78",
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",