omnius 1.0.134 → 1.0.135

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
@@ -1365,7 +1365,7 @@ async function vramSnapshotMB() {
1365
1365
  function getModelBroker() {
1366
1366
  return ModelBroker.getInstance();
1367
1367
  }
1368
- var DEFAULT_RAM_HEADROOM_MB, DEFAULT_VRAM_HEADROOM_MB, DEFAULT_IDLE_EVICT_MS, DEFAULT_POLL_MS, DEFAULT_INFLIGHT_WAIT_MS, ModelBroker, _nvSmiAvailable;
1368
+ var DEFAULT_RAM_HEADROOM_MB, DEFAULT_VRAM_HEADROOM_MB, DEFAULT_IDLE_EVICT_MS, DEFAULT_POLL_MS, DEFAULT_INFLIGHT_WAIT_MS, DEFAULT_SLOT_CAPACITY, DEFAULT_QUEUE_CAPACITY, THROUGHPUT_EMA_ALPHA, THROUGHPUT_INITIAL_TPS, STUCK_INFLIGHT_DIAGNOSTIC_MS, ModelBroker, _nvSmiAvailable;
1369
1369
  var init_model_broker = __esm({
1370
1370
  "packages/execution/dist/model-broker.js"() {
1371
1371
  "use strict";
@@ -1374,6 +1374,11 @@ var init_model_broker = __esm({
1374
1374
  DEFAULT_IDLE_EVICT_MS = 5 * 60 * 1e3;
1375
1375
  DEFAULT_POLL_MS = 4e3;
1376
1376
  DEFAULT_INFLIGHT_WAIT_MS = 6e4;
1377
+ DEFAULT_SLOT_CAPACITY = 4;
1378
+ DEFAULT_QUEUE_CAPACITY = 50;
1379
+ THROUGHPUT_EMA_ALPHA = 0.2;
1380
+ THROUGHPUT_INITIAL_TPS = 25;
1381
+ STUCK_INFLIGHT_DIAGNOSTIC_MS = 5 * 60 * 1e3;
1377
1382
  ModelBroker = class _ModelBroker {
1378
1383
  static _instance = null;
1379
1384
  /** Loaded model registry keyed by `${host}:${name}`. */
@@ -1398,6 +1403,22 @@ var init_model_broker = __esm({
1398
1403
  ramHeadroomMB = DEFAULT_RAM_HEADROOM_MB;
1399
1404
  vramHeadroomMB = DEFAULT_VRAM_HEADROOM_MB;
1400
1405
  idleEvictMs = DEFAULT_IDLE_EVICT_MS;
1406
+ /** Inference slot capacity (auto-tunes from Ollama pool size when known). */
1407
+ slotCapacity = DEFAULT_SLOT_CAPACITY;
1408
+ /** Maximum queue depth before queue pressure is emitted. */
1409
+ queueCapacity = DEFAULT_QUEUE_CAPACITY;
1410
+ // ── Inference slot tracking ─────────────────────────────────────────
1411
+ /** Active slots keyed by slot id. */
1412
+ _activeSlots = /* @__PURE__ */ new Map();
1413
+ /** Reserved slots per sessionKey (1 reserved slot per active chat). */
1414
+ _reservedBySession = /* @__PURE__ */ new Map();
1415
+ // sessionKey -> slot id
1416
+ /** Shared (non-reserved) queue. FIFO with priority insertion. */
1417
+ _slotQueue = [];
1418
+ /** Per-model throughput tracking. */
1419
+ _throughput = /* @__PURE__ */ new Map();
1420
+ /** Monotonic counter for slot ids. */
1421
+ _slotIdSeq = 0;
1401
1422
  static getInstance() {
1402
1423
  if (!_ModelBroker._instance)
1403
1424
  _ModelBroker._instance = new _ModelBroker();
@@ -1876,7 +1897,30 @@ var init_model_broker = __esm({
1876
1897
  inflight: [...this._inflight.entries()].map(([key, v]) => ({ key, owner: v.owner, startedMs: v.startedMs })),
1877
1898
  ramMB: ram,
1878
1899
  vramMB: vram,
1879
- lastPollAt: Date.now()
1900
+ lastPollAt: Date.now(),
1901
+ slots: this.buildSlotsSnapshot()
1902
+ };
1903
+ }
1904
+ buildSlotsSnapshot() {
1905
+ const byModel = {};
1906
+ for (const slot of this._activeSlots.values()) {
1907
+ const k = slot.model;
1908
+ if (!byModel[k])
1909
+ byModel[k] = { inUse: 0, tokensPerSec: 0, samples: 0 };
1910
+ byModel[k].inUse += 1;
1911
+ }
1912
+ for (const [model, tp] of this._throughput) {
1913
+ if (!byModel[model])
1914
+ byModel[model] = { inUse: 0, tokensPerSec: 0, samples: 0 };
1915
+ byModel[model].tokensPerSec = tp.tokensPerSec;
1916
+ byModel[model].samples = tp.samples;
1917
+ }
1918
+ return {
1919
+ inUse: this._activeSlots.size,
1920
+ capacity: this.slotCapacity,
1921
+ queueDepth: this._slotQueue.length,
1922
+ queueCapacity: this.queueCapacity,
1923
+ byModel
1880
1924
  };
1881
1925
  }
1882
1926
  async checkPressure(snap) {
@@ -1890,6 +1934,169 @@ var init_model_broker = __esm({
1890
1934
  this.emit("pressure", "vram", v.free, this.vramHeadroomMB);
1891
1935
  }
1892
1936
  }
1937
+ const queueThreshold = Math.floor(this.queueCapacity * 0.8);
1938
+ if (this._slotQueue.length >= queueThreshold) {
1939
+ this.emit("pressure", "queue", this._slotQueue.length, queueThreshold);
1940
+ }
1941
+ const now = Date.now();
1942
+ for (const slot of this._activeSlots.values()) {
1943
+ if (now - slot.acquiredAt > STUCK_INFLIGHT_DIAGNOSTIC_MS) {
1944
+ }
1945
+ }
1946
+ }
1947
+ // ------------------------------------------------------------------
1948
+ // Inference slot admission control (replaces timeouts)
1949
+ // ------------------------------------------------------------------
1950
+ /**
1951
+ * Acquire an inference slot. Blocks (queues with backpressure) until a slot
1952
+ * is available. Never times out — work either completes or is cancelled
1953
+ * via the caller-provided AbortSignal before admission.
1954
+ *
1955
+ * Two-tier admission:
1956
+ * 1. Reserved: 1 slot per sessionKey kept warm even when shared pool full
1957
+ * 2. Shared: queue with FIFO+priority ordering; size-bounded by queueCapacity
1958
+ *
1959
+ * Backpressure: when queue exceeds 80% capacity, emit `pressure: "queue"` —
1960
+ * upstream callers (e.g. Telegram poll loop) should slow ingress.
1961
+ */
1962
+ acquireInferenceSlot(spec) {
1963
+ if (this._activeSlots.size < this.slotCapacity) {
1964
+ return Promise.resolve(this.admitSlot(
1965
+ spec,
1966
+ /*reserved*/
1967
+ false
1968
+ ));
1969
+ }
1970
+ if (spec.sessionKey && !this._reservedBySession.has(spec.sessionKey) && this._activeSlots.size < this.slotCapacity + 1) {
1971
+ const slot = this.admitSlot(
1972
+ spec,
1973
+ /*reserved*/
1974
+ true
1975
+ );
1976
+ this._reservedBySession.set(spec.sessionKey, slot.info.id);
1977
+ return Promise.resolve(slot);
1978
+ }
1979
+ return new Promise((resolve55, reject) => {
1980
+ const entry = { spec, resolve: resolve55, reject, enqueuedAt: Date.now() };
1981
+ if (spec.signal) {
1982
+ const onAbort = () => {
1983
+ const idx = this._slotQueue.indexOf(entry);
1984
+ if (idx >= 0)
1985
+ this._slotQueue.splice(idx, 1);
1986
+ reject(new Error("inference slot acquisition aborted by caller signal"));
1987
+ };
1988
+ if (spec.signal.aborted) {
1989
+ onAbort();
1990
+ return;
1991
+ }
1992
+ spec.signal.addEventListener("abort", onAbort, { once: true });
1993
+ entry.onSignalAbort = onAbort;
1994
+ }
1995
+ const prio = spec.priority ?? 0;
1996
+ let insertAt = this._slotQueue.length;
1997
+ for (let i2 = this._slotQueue.length - 1; i2 >= 0; i2--) {
1998
+ const p2 = this._slotQueue[i2].spec.priority ?? 0;
1999
+ if (p2 >= prio) {
2000
+ insertAt = i2 + 1;
2001
+ break;
2002
+ }
2003
+ if (i2 === 0)
2004
+ insertAt = 0;
2005
+ }
2006
+ this._slotQueue.splice(insertAt, 0, entry);
2007
+ const threshold = Math.floor(this.queueCapacity * 0.8);
2008
+ if (this._slotQueue.length === threshold) {
2009
+ this.emit("pressure", "queue", this._slotQueue.length, threshold);
2010
+ }
2011
+ });
2012
+ }
2013
+ /** Admit a slot — internal, called from acquire fast path and from drainQueue. */
2014
+ admitSlot(spec, reserved) {
2015
+ const id = `slot-${++this._slotIdSeq}-${Date.now().toString(36)}`;
2016
+ const info = {
2017
+ id,
2018
+ model: spec.model,
2019
+ domain: spec.domain,
2020
+ owner: spec.owner,
2021
+ sessionKey: spec.sessionKey,
2022
+ acquiredAt: Date.now(),
2023
+ promptTokens: spec.promptTokens ?? 0,
2024
+ reserved
2025
+ };
2026
+ this._activeSlots.set(id, info);
2027
+ this.emit("slotAcquired", info);
2028
+ let released = false;
2029
+ const broker = this;
2030
+ return {
2031
+ info,
2032
+ release(outcome) {
2033
+ if (released)
2034
+ return;
2035
+ released = true;
2036
+ broker.releaseSlot(info, outcome);
2037
+ }
2038
+ };
2039
+ }
2040
+ releaseSlot(info, outcome) {
2041
+ this._activeSlots.delete(info.id);
2042
+ if (info.sessionKey && this._reservedBySession.get(info.sessionKey) === info.id) {
2043
+ this._reservedBySession.delete(info.sessionKey);
2044
+ }
2045
+ if (outcome.ok && (outcome.completionTokens ?? 0) > 0) {
2046
+ const wallMs = Date.now() - info.acquiredAt;
2047
+ if (wallMs > 100) {
2048
+ const tps = outcome.completionTokens * 1e3 / wallMs;
2049
+ const cur = this._throughput.get(info.model) ?? {
2050
+ tokensPerSec: THROUGHPUT_INITIAL_TPS,
2051
+ samples: 0,
2052
+ lastReleaseAt: 0
2053
+ };
2054
+ cur.tokensPerSec = cur.samples === 0 ? tps : cur.tokensPerSec * (1 - THROUGHPUT_EMA_ALPHA) + tps * THROUGHPUT_EMA_ALPHA;
2055
+ cur.samples += 1;
2056
+ cur.lastReleaseAt = Date.now();
2057
+ this._throughput.set(info.model, cur);
2058
+ this.emit("throughputUpdated", info.model, cur.tokensPerSec);
2059
+ }
2060
+ }
2061
+ this.emit("slotReleased", info, outcome);
2062
+ this.drainSlotQueue();
2063
+ }
2064
+ drainSlotQueue() {
2065
+ while (this._slotQueue.length > 0 && this._activeSlots.size < this.slotCapacity) {
2066
+ const entry = this._slotQueue.shift();
2067
+ if (entry.onSignalAbort && entry.spec.signal) {
2068
+ entry.spec.signal.removeEventListener("abort", entry.onSignalAbort);
2069
+ }
2070
+ if (entry.spec.signal?.aborted) {
2071
+ try {
2072
+ entry.reject(new Error("aborted before admission"));
2073
+ } catch {
2074
+ }
2075
+ continue;
2076
+ }
2077
+ const slot = this.admitSlot(
2078
+ entry.spec,
2079
+ /*reserved*/
2080
+ false
2081
+ );
2082
+ try {
2083
+ entry.resolve(slot);
2084
+ } catch {
2085
+ }
2086
+ }
2087
+ }
2088
+ /** Snapshot of throughput EMAs (for /broker and debugging). */
2089
+ throughputByModel() {
2090
+ const out = {};
2091
+ for (const [model, tp] of this._throughput) {
2092
+ out[model] = { tokensPerSec: tp.tokensPerSec, samples: tp.samples };
2093
+ }
2094
+ return out;
2095
+ }
2096
+ /** Tune the shared slot capacity at runtime (e.g. when Ollama pool resizes). */
2097
+ setSlotCapacity(n2) {
2098
+ this.slotCapacity = Math.max(1, Math.floor(n2));
2099
+ this.drainSlotQueue();
1893
2100
  }
1894
2101
  keyOf(spec) {
1895
2102
  return `${spec.host}:${spec.name}`;
@@ -1899,6 +2106,115 @@ var init_model_broker = __esm({
1899
2106
  }
1900
2107
  });
1901
2108
 
2109
+ // packages/execution/dist/broker-mediated-backend.js
2110
+ function wrapWithBroker(backend, options2) {
2111
+ const broker = getModelBroker();
2112
+ const clamp7 = options2.clampNumCtx !== false;
2113
+ const wrapped = Object.create(backend);
2114
+ wrapped.chatCompletion = async (request) => {
2115
+ const model = backend.model || request.model || "unknown";
2116
+ let effectiveRequest = request;
2117
+ if (clamp7) {
2118
+ const trainCtx = await broker.getNctxTrain(model).catch(() => null);
2119
+ const requestedNumCtx = request.numCtx;
2120
+ if (trainCtx && trainCtx > 0) {
2121
+ const target = requestedNumCtx ? Math.min(requestedNumCtx, trainCtx) : Math.min(trainCtx, estimateContextNeed(request));
2122
+ if (target > 0) {
2123
+ effectiveRequest = { ...request, numCtx: target };
2124
+ }
2125
+ }
2126
+ }
2127
+ const promptTokens = estimatePromptTokens(request);
2128
+ const slot = await broker.acquireInferenceSlot({
2129
+ model,
2130
+ domain: options2.domain,
2131
+ owner: options2.owner,
2132
+ sessionKey: options2.sessionKey,
2133
+ promptTokens,
2134
+ priority: options2.priority ?? 0
2135
+ });
2136
+ try {
2137
+ const result = await backend.chatCompletion(effectiveRequest);
2138
+ const usage = result.usage;
2139
+ slot.release({ ok: true, completionTokens: usage?.completion_tokens ?? 0 });
2140
+ return result;
2141
+ } catch (err) {
2142
+ slot.release({ ok: false, error: err instanceof Error ? err.message : String(err) });
2143
+ throw err;
2144
+ }
2145
+ };
2146
+ if (typeof backend.chatCompletionStream === "function") {
2147
+ const streamFn = backend.chatCompletionStream.bind(backend);
2148
+ wrapped.chatCompletionStream = async function* (request) {
2149
+ const model = backend.model || request.model || "unknown";
2150
+ let effectiveRequest = request;
2151
+ if (clamp7) {
2152
+ const trainCtx = await broker.getNctxTrain(model).catch(() => null);
2153
+ const requestedNumCtx = request.numCtx;
2154
+ if (trainCtx && trainCtx > 0) {
2155
+ const target = requestedNumCtx ? Math.min(requestedNumCtx, trainCtx) : Math.min(trainCtx, estimateContextNeed(request));
2156
+ if (target > 0)
2157
+ effectiveRequest = { ...request, numCtx: target };
2158
+ }
2159
+ }
2160
+ const promptTokens = estimatePromptTokens(request);
2161
+ const slot = await broker.acquireInferenceSlot({
2162
+ model,
2163
+ domain: options2.domain,
2164
+ owner: options2.owner,
2165
+ sessionKey: options2.sessionKey,
2166
+ promptTokens,
2167
+ priority: options2.priority ?? 0
2168
+ });
2169
+ let completionTokens = 0;
2170
+ try {
2171
+ for await (const chunk of streamFn(effectiveRequest)) {
2172
+ const usage = chunk.usage;
2173
+ if (usage?.completion_tokens)
2174
+ completionTokens = usage.completion_tokens;
2175
+ yield chunk;
2176
+ }
2177
+ slot.release({ ok: true, completionTokens });
2178
+ } catch (err) {
2179
+ slot.release({ ok: false, error: err instanceof Error ? err.message : String(err) });
2180
+ throw err;
2181
+ }
2182
+ };
2183
+ }
2184
+ return wrapped;
2185
+ }
2186
+ function estimatePromptTokens(request) {
2187
+ let chars = 0;
2188
+ if (Array.isArray(request?.messages)) {
2189
+ for (const m2 of request.messages) {
2190
+ if (typeof m2.content === "string")
2191
+ chars += m2.content.length;
2192
+ else if (Array.isArray(m2.content)) {
2193
+ for (const part of m2.content) {
2194
+ if (typeof part?.text === "string")
2195
+ chars += part.text.length;
2196
+ }
2197
+ }
2198
+ chars += 8;
2199
+ }
2200
+ }
2201
+ if (Array.isArray(request?.tools) && request.tools.length > 0) {
2202
+ chars += request.tools.length * 600;
2203
+ }
2204
+ return Math.ceil(chars / 4);
2205
+ }
2206
+ function estimateContextNeed(request) {
2207
+ const promptTokens = estimatePromptTokens(request);
2208
+ const maxTokens = request?.maxTokens ?? 1024;
2209
+ return Math.max(2048, promptTokens + maxTokens + 512);
2210
+ }
2211
+ var init_broker_mediated_backend = __esm({
2212
+ "packages/execution/dist/broker-mediated-backend.js"() {
2213
+ "use strict";
2214
+ init_model_broker();
2215
+ }
2216
+ });
2217
+
1902
2218
  // packages/execution/dist/tools/security-classifier.js
1903
2219
  function classifyTool(name10) {
1904
2220
  for (const rule of RULES) {
@@ -525416,6 +525732,7 @@ __export(dist_exports, {
525416
525732
  videoGenerationQualityLadder: () => videoGenerationQualityLadder,
525417
525733
  videoGenerationSetupPlan: () => videoGenerationSetupPlan,
525418
525734
  worktreeHasChanges: () => worktreeHasChanges,
525735
+ wrapWithBroker: () => wrapWithBroker,
525419
525736
  writeProvenanceFile: () => writeProvenanceFile,
525420
525737
  writeTodos: () => writeTodos
525421
525738
  });
@@ -525424,6 +525741,7 @@ var init_dist5 = __esm({
525424
525741
  "use strict";
525425
525742
  init_tool_executor();
525426
525743
  init_model_broker();
525744
+ init_broker_mediated_backend();
525427
525745
  init_security_classifier();
525428
525746
  init_tool_manifest();
525429
525747
  init_provenance();
@@ -555275,6 +555593,13 @@ ${description}`
555275
555593
  if (responseFormat !== void 0) {
555276
555594
  body["response_format"] = responseFormat;
555277
555595
  }
555596
+ const reqNumCtx = request.numCtx;
555597
+ if (Number.isFinite(reqNumCtx) && (reqNumCtx ?? 0) > 0) {
555598
+ const opts = body["options"] ?? {};
555599
+ opts["num_ctx"] = reqNumCtx;
555600
+ body["options"] = opts;
555601
+ body["num_ctx"] = reqNumCtx;
555602
+ }
555278
555603
  let poolSlot = shouldUseOllamaPoolForBaseUrl(this.baseUrl) ? await getOllamaPool({ baseInstanceUrl: this.baseUrl }).acquire({
555279
555604
  model: this.model
555280
555605
  }) : null;
@@ -615178,6 +615503,300 @@ var init_stimulation = __esm({
615178
615503
  }
615179
615504
  });
615180
615505
 
615506
+ // packages/cli/src/tui/pid-controller.ts
615507
+ function clamp018(x) {
615508
+ if (!Number.isFinite(x)) return 0;
615509
+ if (x < 0) return 0;
615510
+ if (x > 1) return 1;
615511
+ return x;
615512
+ }
615513
+ function getPidRegistry() {
615514
+ if (!_registry2) _registry2 = new PidRegistry();
615515
+ return _registry2;
615516
+ }
615517
+ var DEFAULT_PID_CONFIG, PidRegistry, _registry2;
615518
+ var init_pid_controller = __esm({
615519
+ "packages/cli/src/tui/pid-controller.ts"() {
615520
+ "use strict";
615521
+ DEFAULT_PID_CONFIG = {
615522
+ kp: 1e-4,
615523
+ ki: 1e-5,
615524
+ kd: 0,
615525
+ setpointMs: 8e3,
615526
+ initialOutput: 1,
615527
+ pvEmaAlpha: 0.3,
615528
+ integralClamp: 5e3
615529
+ // ms*s — bounds integral term contribution
615530
+ };
615531
+ PidRegistry = class {
615532
+ _controllers = /* @__PURE__ */ new Map();
615533
+ /** Get or create a controller. */
615534
+ get(key, configOverride) {
615535
+ let st = this._controllers.get(key);
615536
+ if (!st) {
615537
+ const config = { ...DEFAULT_PID_CONFIG, ...configOverride ?? {} };
615538
+ st = {
615539
+ output: config.initialOutput,
615540
+ pv: config.setpointMs,
615541
+ // assume on-target at startup
615542
+ integral: 0,
615543
+ lastError: 0,
615544
+ lastSampleAt: 0,
615545
+ samples: 0,
615546
+ config
615547
+ };
615548
+ this._controllers.set(key, st);
615549
+ }
615550
+ return st;
615551
+ }
615552
+ /** Read-only current output (inclusion ratio in [0,1]). */
615553
+ output(key) {
615554
+ return this._controllers.get(key)?.output ?? DEFAULT_PID_CONFIG.initialOutput;
615555
+ }
615556
+ /**
615557
+ * Record a new latency sample (in ms) and update the controller.
615558
+ * Returns the new output value.
615559
+ */
615560
+ sample(key, latencyMs, configOverride) {
615561
+ const st = this.get(key, configOverride);
615562
+ const now = Date.now();
615563
+ st.pv = st.samples === 0 ? latencyMs : st.pv * (1 - st.config.pvEmaAlpha) + latencyMs * st.config.pvEmaAlpha;
615564
+ const error = st.config.setpointMs - st.pv;
615565
+ st.integral += error;
615566
+ if (st.integral > st.config.integralClamp) st.integral = st.config.integralClamp;
615567
+ if (st.integral < -st.config.integralClamp) st.integral = -st.config.integralClamp;
615568
+ const dt = st.lastSampleAt > 0 ? now - st.lastSampleAt : 1e3;
615569
+ const derivative = dt > 0 ? (error - st.lastError) / dt : 0;
615570
+ const u = st.config.kp * error + st.config.ki * st.integral + st.config.kd * derivative;
615571
+ st.output = clamp018(st.output + u);
615572
+ st.lastError = error;
615573
+ st.lastSampleAt = now;
615574
+ st.samples += 1;
615575
+ return st.output;
615576
+ }
615577
+ /** All controller snapshots — for /broker debug surface. */
615578
+ snapshot() {
615579
+ return [...this._controllers.entries()].map(([key, st]) => ({
615580
+ key,
615581
+ output: st.output,
615582
+ pv: st.pv,
615583
+ setpoint: st.config.setpointMs,
615584
+ samples: st.samples
615585
+ }));
615586
+ }
615587
+ /** Reset (test-only). */
615588
+ reset() {
615589
+ this._controllers.clear();
615590
+ }
615591
+ };
615592
+ _registry2 = null;
615593
+ }
615594
+ });
615595
+
615596
+ // packages/cli/src/tui/component-benefit.ts
615597
+ function getComponentBenefitRegistry() {
615598
+ if (!_registry3) _registry3 = new ComponentBenefitRegistry();
615599
+ return _registry3;
615600
+ }
615601
+ var EMA_ALPHA, MIN_SAMPLES_TO_TRUST, ComponentBenefitRegistry, _registry3;
615602
+ var init_component_benefit = __esm({
615603
+ "packages/cli/src/tui/component-benefit.ts"() {
615604
+ "use strict";
615605
+ EMA_ALPHA = 0.2;
615606
+ MIN_SAMPLES_TO_TRUST = 3;
615607
+ ComponentBenefitRegistry = class {
615608
+ /** Two-tier map: chatKey → componentKey → state. */
615609
+ _byChat = /* @__PURE__ */ new Map();
615610
+ /** Score for a component in a chat. Returns 0.5 (neutral) when not enough samples. */
615611
+ score(chatKey, componentKey) {
615612
+ const st = this._byChat.get(chatKey)?.get(componentKey);
615613
+ if (!st || st.samples < MIN_SAMPLES_TO_TRUST) return 0.5;
615614
+ return st.score;
615615
+ }
615616
+ /** Record one batch — for each sampled component, did the decision text reference its needle? */
615617
+ recordOutcome(chatKey, samples, decisionText) {
615618
+ const haystack = decisionText.toLowerCase();
615619
+ let map2 = this._byChat.get(chatKey);
615620
+ if (!map2) {
615621
+ map2 = /* @__PURE__ */ new Map();
615622
+ this._byChat.set(chatKey, map2);
615623
+ }
615624
+ const now = Date.now();
615625
+ for (const sample of samples) {
615626
+ const needle = sample.needle.toLowerCase();
615627
+ const hit = needle.length >= 3 && haystack.includes(needle);
615628
+ let st = map2.get(sample.key);
615629
+ if (!st) {
615630
+ st = { score: 0.5, samples: 0, hits: 0, lastSeenAt: now };
615631
+ map2.set(sample.key, st);
615632
+ }
615633
+ const newScore = hit ? 1 : 0;
615634
+ st.score = st.samples === 0 ? newScore : st.score * (1 - EMA_ALPHA) + newScore * EMA_ALPHA;
615635
+ st.samples += 1;
615636
+ st.hits += hit ? 1 : 0;
615637
+ st.lastSeenAt = now;
615638
+ }
615639
+ }
615640
+ /** Snapshot for /broker debug surface. */
615641
+ snapshot(chatKey) {
615642
+ const out = [];
615643
+ const iterate = chatKey ? [[chatKey, this._byChat.get(chatKey)]].filter((e2) => !!e2[1]) : [...this._byChat.entries()];
615644
+ for (const [cKey, map2] of iterate) {
615645
+ for (const [comp, st] of map2) {
615646
+ out.push({ chatKey: cKey, componentKey: comp, score: st.score, samples: st.samples, hits: st.hits });
615647
+ }
615648
+ }
615649
+ return out;
615650
+ }
615651
+ reset() {
615652
+ this._byChat.clear();
615653
+ }
615654
+ };
615655
+ _registry3 = null;
615656
+ }
615657
+ });
615658
+
615659
+ // packages/cli/src/tui/soul-observations.ts
615660
+ function getSoulObservationStream() {
615661
+ if (!_stream) {
615662
+ _stream = new SoulObservationStream();
615663
+ subscribeBrokerEvents(_stream);
615664
+ }
615665
+ return _stream;
615666
+ }
615667
+ function subscribeBrokerEvents(stream) {
615668
+ if (_brokerSubscribed) return;
615669
+ _brokerSubscribed = true;
615670
+ const broker = getModelBroker();
615671
+ broker.on("slotReleased", (info, outcome) => {
615672
+ if (outcome.ok) {
615673
+ stream.emit({
615674
+ kind: "inference.completed",
615675
+ model: info.model,
615676
+ sessionKey: info.sessionKey,
615677
+ latencyMs: Date.now() - info.acquiredAt,
615678
+ promptTokens: info.promptTokens,
615679
+ completionTokens: outcome.completionTokens ?? 0,
615680
+ ts: Date.now()
615681
+ });
615682
+ } else {
615683
+ stream.emit({
615684
+ kind: "inference.degraded",
615685
+ model: info.model,
615686
+ sessionKey: info.sessionKey,
615687
+ reason: outcome.error ?? "unknown",
615688
+ ts: Date.now()
615689
+ });
615690
+ }
615691
+ });
615692
+ broker.on("pressure", (kind, value2, threshold) => {
615693
+ stream.emit({ kind: "broker.pressure", pressure: kind, value: value2, threshold, ts: Date.now() });
615694
+ });
615695
+ broker.on("evicted", (m2, reason) => {
615696
+ stream.emit({ kind: "model.evicted", host: m2.host, name: m2.name, reason, ts: Date.now() });
615697
+ });
615698
+ }
615699
+ function formatSystemObservations(sessionKey) {
615700
+ const stream = getSoulObservationStream();
615701
+ const broker = getModelBroker();
615702
+ const snap = broker.snapshot();
615703
+ const pidSnap = getPidRegistry().snapshot();
615704
+ const lines = [];
615705
+ const slots = snap.slots;
615706
+ const utilPct = slots.capacity > 0 ? Math.round(slots.inUse / slots.capacity * 100) : 0;
615707
+ const tpsByModel = Object.entries(slots.byModel).filter(([, m2]) => m2.samples > 0).map(([model, m2]) => `${model}=${m2.tokensPerSec.toFixed(1)}t/s (${m2.samples}s)`).join(", ");
615708
+ if (slots.inUse > 0 || slots.queueDepth > 0 || tpsByModel) {
615709
+ lines.push(`Capacity: ${slots.inUse}/${slots.capacity} slots in use (${utilPct}%), queue=${slots.queueDepth}/${slots.queueCapacity}${tpsByModel ? `; throughput: ${tpsByModel}` : ""}.`);
615710
+ }
615711
+ if (snap.ramMB.free < (broker.ramHeadroomMB ?? 0)) {
615712
+ lines.push(`RAM pressure: ${snap.ramMB.free}MB free (below ${broker.ramHeadroomMB}MB headroom).`);
615713
+ }
615714
+ if (snap.vramMB && snap.vramMB.free < (broker.vramHeadroomMB ?? 0)) {
615715
+ lines.push(`VRAM pressure: ${snap.vramMB.free}MB free (below ${broker.vramHeadroomMB}MB headroom).`);
615716
+ }
615717
+ const queueThreshold = Math.floor(snap.slots.queueCapacity * 0.8);
615718
+ if (snap.slots.queueDepth >= queueThreshold) {
615719
+ lines.push(`Queue pressure: ${snap.slots.queueDepth}/${snap.slots.queueCapacity} entries — prefer brief replies or single-emoji reactions to keep the queue draining.`);
615720
+ }
615721
+ const interesting = pidSnap.filter((p2) => p2.samples >= 3 && (p2.output < 0.95 || p2.output > 1.05));
615722
+ if (interesting.length > 0) {
615723
+ const pidLines = interesting.slice(0, 4).map((p2) => `${p2.key}: u=${p2.output.toFixed(2)} (pv=${Math.round(p2.pv)}ms, sp=${p2.setpoint}ms)`).join(", ");
615724
+ lines.push(`Context tier PID state: ${pidLines}.`);
615725
+ }
615726
+ if (sessionKey) {
615727
+ const recent = stream.recentForSession(sessionKey, 15);
615728
+ if (recent.length > 0) {
615729
+ const sends = recent.filter((e2) => e2.kind.startsWith("telegram.send."));
615730
+ const reactions = recent.filter((e2) => e2.kind.startsWith("emoji."));
615731
+ const forbidden = sends.filter((e2) => e2.kind === "telegram.send.forbidden").length;
615732
+ const rateLimited = sends.filter((e2) => e2.kind === "telegram.send.rate_limited").length;
615733
+ if (forbidden > 0) lines.push(`This chat has refused ${forbidden} recent send attempt(s) (e.g. no rights to post). Treat as a strong silence signal.`);
615734
+ if (rateLimited > 0) lines.push(`This chat rate-limited ${rateLimited} recent send(s). Slow cadence.`);
615735
+ if (reactions.length > 0) {
615736
+ const reactSummary = reactions.filter((e2) => e2.kind === "emoji.reaction.received").map((e2) => e2.emoji).join("");
615737
+ if (reactSummary) lines.push(`Recent inbound reactions in this chat: ${reactSummary}`);
615738
+ }
615739
+ }
615740
+ }
615741
+ if (lines.length === 0) return "";
615742
+ return ["## System Observations (broker, PID, capacity, send outcomes)", ...lines].join("\n");
615743
+ }
615744
+ var PER_SESSION_BUFFER, GLOBAL_BUFFER, SoulObservationStream, _stream, _brokerSubscribed;
615745
+ var init_soul_observations = __esm({
615746
+ "packages/cli/src/tui/soul-observations.ts"() {
615747
+ "use strict";
615748
+ init_dist5();
615749
+ init_pid_controller();
615750
+ PER_SESSION_BUFFER = 60;
615751
+ GLOBAL_BUFFER = 200;
615752
+ SoulObservationStream = class {
615753
+ _bySession = /* @__PURE__ */ new Map();
615754
+ _global = [];
615755
+ _listeners = /* @__PURE__ */ new Set();
615756
+ /** Record an event. */
615757
+ emit(event) {
615758
+ if ("sessionKey" in event && event.sessionKey) {
615759
+ let buf = this._bySession.get(event.sessionKey);
615760
+ if (!buf) {
615761
+ buf = [];
615762
+ this._bySession.set(event.sessionKey, buf);
615763
+ }
615764
+ buf.push(event);
615765
+ if (buf.length > PER_SESSION_BUFFER) buf.shift();
615766
+ }
615767
+ this._global.push(event);
615768
+ if (this._global.length > GLOBAL_BUFFER) this._global.shift();
615769
+ for (const listener of this._listeners) {
615770
+ try {
615771
+ listener(event);
615772
+ } catch {
615773
+ }
615774
+ }
615775
+ }
615776
+ /** Subscribe to all events (live tail). */
615777
+ subscribe(listener) {
615778
+ this._listeners.add(listener);
615779
+ return () => this._listeners.delete(listener);
615780
+ }
615781
+ /** Read recent events for a session (most recent last). */
615782
+ recentForSession(sessionKey, limit = 20) {
615783
+ const buf = this._bySession.get(sessionKey) ?? [];
615784
+ return buf.slice(-limit);
615785
+ }
615786
+ /** Read recent global events. */
615787
+ recentGlobal(limit = 30) {
615788
+ return this._global.slice(-limit);
615789
+ }
615790
+ reset() {
615791
+ this._bySession.clear();
615792
+ this._global.length = 0;
615793
+ }
615794
+ };
615795
+ _stream = null;
615796
+ _brokerSubscribed = false;
615797
+ }
615798
+ });
615799
+
615181
615800
  // packages/cli/src/tui/telegram-channel-dmn.ts
615182
615801
  import { existsSync as existsSync115, mkdirSync as mkdirSync65, readdirSync as readdirSync40, readFileSync as readFileSync94, writeFileSync as writeFileSync59 } from "node:fs";
615183
615802
  import { join as join129 } from "node:path";
@@ -615276,7 +615895,7 @@ function buildReplyOpportunities(input, openQuestions) {
615276
615895
  function daydreamOpportunityId(input, trigger) {
615277
615896
  return createHash23("sha1").update(`${input.sessionKey}:${input.generatedAtMs}:${trigger}`).digest("hex").slice(0, 16);
615278
615897
  }
615279
- function clamp018(value2) {
615898
+ function clamp019(value2) {
615280
615899
  if (!Number.isFinite(value2)) return 0;
615281
615900
  return Math.max(0, Math.min(1, value2));
615282
615901
  }
@@ -615287,7 +615906,7 @@ function pushStimulationSignal(signals, signal, source, weight) {
615287
615906
  const cleanSignal = compactLine2(signal, 120);
615288
615907
  const cleanSource = compactLine2(source, 180);
615289
615908
  if (!cleanSignal || signals.some((entry) => entry.signal === cleanSignal && entry.source === cleanSource)) return;
615290
- signals.push({ signal: cleanSignal, source: cleanSource, weight: clamp018(weight) });
615909
+ signals.push({ signal: cleanSignal, source: cleanSource, weight: clamp019(weight) });
615291
615910
  }
615292
615911
  function buildMetaAnalysisSignals(input) {
615293
615912
  const chatLabel = input.chatTitle || input.chatId;
@@ -615362,7 +615981,7 @@ function buildCuriosityThreads(input, openQuestions, stimulationSignals) {
615362
615981
  question: text.endsWith("?") || text.endsWith("?") ? text : `What should be learned or clarified from: ${text || entry.mediaSummary || "recent media"}?`,
615363
615982
  rationale: "Human curiosity, uncertainty, or multimodal content makes this a useful idle exploration target.",
615364
615983
  sourceMessages: messageId,
615365
- intensity: clamp018(0.5 + replyBoost + mediaBoost + questionBoost)
615984
+ intensity: clamp019(0.5 + replyBoost + mediaBoost + questionBoost)
615366
615985
  });
615367
615986
  }
615368
615987
  for (const question of openQuestions.slice(-4)) {
@@ -615382,7 +616001,7 @@ function buildCuriosityThreads(input, openQuestions, stimulationSignals) {
615382
616001
  question: `Is there a useful clarification or memory consolidation around ${strongest.source}?`,
615383
616002
  rationale: "Strongest stimulation signal can seed a low-intrusion reflection target.",
615384
616003
  sourceMessages: [],
615385
- intensity: clamp018(strongest.weight * 0.72)
616004
+ intensity: clamp019(strongest.weight * 0.72)
615386
616005
  });
615387
616006
  }
615388
616007
  return threads.sort((a2, b) => b.intensity - a2.intensity).slice(0, 8);
@@ -615456,7 +616075,7 @@ function buildOutreachPlans(input, curiosityThreads) {
615456
616075
  purpose: "Continue the public thread only when the live model judges that the group would benefit from a concise follow-up.",
615457
616076
  draftIntent: "Ask one concrete clarification, offer one useful synthesis, or stay silent if the room has moved on.",
615458
616077
  gate: "model_decision",
615459
- confidence: clamp018(thread.intensity * 0.86)
616078
+ confidence: clamp019(thread.intensity * 0.86)
615460
616079
  });
615461
616080
  const participant = participantForThread(input, thread);
615462
616081
  if (!participant) continue;
@@ -615468,7 +616087,7 @@ function buildOutreachPlans(input, curiosityThreads) {
615468
616087
  purpose: "Offer a one-to-one follow-up only if private contact is allowed and the issue is personal, unresolved, or better handled outside the group.",
615469
616088
  draftIntent: "Reference the public thread briefly, ask permission to continue privately, and do not reveal hidden meta-analysis.",
615470
616089
  gate: "admin_review",
615471
- confidence: clamp018(thread.intensity * 0.58)
616090
+ confidence: clamp019(thread.intensity * 0.58)
615472
616091
  });
615473
616092
  }
615474
616093
  return plans.slice(0, 8);
@@ -616571,7 +617190,7 @@ function numberOr(value2, fallback) {
616571
617190
  function isNumber(value2) {
616572
617191
  return typeof value2 === "number" && Number.isFinite(value2);
616573
617192
  }
616574
- function clamp019(value2) {
617193
+ function clamp0110(value2) {
616575
617194
  return Math.max(0, Math.min(1, Number.isFinite(value2) ? value2 : 0));
616576
617195
  }
616577
617196
  function iso(ts) {
@@ -616718,8 +617337,8 @@ function normalizeRelationship(raw) {
616718
617337
  kind: value2.kind,
616719
617338
  fromKey: String(value2.fromKey),
616720
617339
  toKey: String(value2.toKey),
616721
- confidence: clamp019(numberOr(value2.confidence, 0)),
616722
- weight: clamp019(numberOr(value2.weight, 0)),
617340
+ confidence: clamp0110(numberOr(value2.confidence, 0)),
617341
+ weight: clamp0110(numberOr(value2.weight, 0)),
616723
617342
  firstSeenAt: numberOr(value2.firstSeenAt, Date.now()),
616724
617343
  lastSeenAt: numberOr(value2.lastSeenAt, Date.now()),
616725
617344
  evidenceMessageIds: Array.isArray(value2.evidenceMessageIds) ? value2.evidenceMessageIds.filter(isNumber).slice(-40) : [],
@@ -616738,7 +617357,7 @@ function normalizePreferences(raw) {
616738
617357
  if (!evidence || typeof evidence !== "object") continue;
616739
617358
  out[actorKey][key] = {
616740
617359
  value: Math.max(-1, Math.min(1, numberOr(evidence.value, 0))),
616741
- confidence: clamp019(numberOr(evidence.confidence, 0)),
617360
+ confidence: clamp0110(numberOr(evidence.confidence, 0)),
616742
617361
  updatedAt: numberOr(evidence.updatedAt, Date.now()),
616743
617362
  evidenceMessageIds: Array.isArray(evidence.evidenceMessageIds) ? evidence.evidenceMessageIds.filter(isNumber).slice(-12) : [],
616744
617363
  note: compactOptional(evidence.note, 220)
@@ -616796,7 +617415,7 @@ function normalizeOutcome(raw) {
616796
617415
  replyToMessageId: typeof value2.replyToMessageId === "number" ? value2.replyToMessageId : void 0,
616797
617416
  route: value2.route === "action" ? "action" : "chat",
616798
617417
  shouldReply: value2.shouldReply === true,
616799
- confidence: clamp019(numberOr(value2.confidence, 0)),
617418
+ confidence: clamp0110(numberOr(value2.confidence, 0)),
616800
617419
  reason: compact2(value2.reason || "", 280),
616801
617420
  source: compact2(value2.source || "unknown", 80),
616802
617421
  silentDisposition: compactOptional(value2.silentDisposition, 280),
@@ -616808,7 +617427,7 @@ function normalizeOutcome(raw) {
616808
617427
  scenarioNote: compactOptional(value2.scenarioNote, 360),
616809
617428
  scenarioId: compactOptional(value2.scenarioId, 160),
616810
617429
  scenarioLabel: compactOptional(value2.scenarioLabel, 160),
616811
- scenarioConfidence: typeof value2.scenarioConfidence === "number" && Number.isFinite(value2.scenarioConfidence) ? clamp019(value2.scenarioConfidence) : void 0,
617430
+ scenarioConfidence: typeof value2.scenarioConfidence === "number" && Number.isFinite(value2.scenarioConfidence) ? clamp0110(value2.scenarioConfidence) : void 0,
616812
617431
  scenarioObjective: compactOptional(value2.scenarioObjective, 360),
616813
617432
  scenarioStateLoop: compactOptional(value2.scenarioStateLoop, 360),
616814
617433
  salienceSignals: Array.isArray(value2.salienceSignals) ? value2.salienceSignals.map(String).slice(0, 16) : [],
@@ -616826,7 +617445,7 @@ function normalizeDaydreamOpportunity(raw) {
616826
617445
  artifactId: String(value2.artifactId || "unknown"),
616827
617446
  generatedAt: String(value2.generatedAt || (/* @__PURE__ */ new Date()).toISOString()),
616828
617447
  trigger: compact2(value2.trigger || "", 240),
616829
- confidence: clamp019(numberOr(value2.confidence, 0)),
617448
+ confidence: clamp0110(numberOr(value2.confidence, 0)),
616830
617449
  lifecycle,
616831
617450
  firstSeenAt: numberOr(value2.firstSeenAt, Date.now()),
616832
617451
  updatedAt: numberOr(value2.updatedAt, Date.now()),
@@ -616883,7 +617502,7 @@ function commitTelegramSocialDecision(state, input) {
616883
617502
  replyToMessageId: input.replyToMessageId,
616884
617503
  route: input.route,
616885
617504
  shouldReply: input.shouldReply,
616886
- confidence: clamp019(input.confidence),
617505
+ confidence: clamp0110(input.confidence),
616887
617506
  reason: compact2(input.reason, 280),
616888
617507
  source: compact2(input.source, 80),
616889
617508
  silentDisposition: compactOptional(input.silentDisposition, 280),
@@ -616895,7 +617514,7 @@ function commitTelegramSocialDecision(state, input) {
616895
617514
  scenarioNote: compactOptional(input.scenarioNote, 360),
616896
617515
  scenarioId: compactOptional(input.scenarioId, 160),
616897
617516
  scenarioLabel: compactOptional(input.scenarioLabel, 160),
616898
- scenarioConfidence: input.scenarioConfidence === void 0 ? void 0 : clamp019(input.scenarioConfidence),
617517
+ scenarioConfidence: input.scenarioConfidence === void 0 ? void 0 : clamp0110(input.scenarioConfidence),
616899
617518
  scenarioObjective: compactOptional(input.scenarioObjective, 360),
616900
617519
  scenarioStateLoop: compactOptional(input.scenarioStateLoop, 360),
616901
617520
  salienceSignals: [...new Set((input.salienceSignals ?? []).map(String))].slice(0, 16),
@@ -616919,7 +617538,7 @@ function registerDaydreamOpportunities(state, opportunities, now = Date.now()) {
616919
617538
  artifactId: opportunity.artifactId || "unknown",
616920
617539
  generatedAt: opportunity.generatedAt || new Date(now).toISOString(),
616921
617540
  trigger: compact2(opportunity.trigger, 240),
616922
- confidence: clamp019(opportunity.confidence),
617541
+ confidence: clamp0110(opportunity.confidence),
616923
617542
  lifecycle: "proposed",
616924
617543
  firstSeenAt: now,
616925
617544
  updatedAt: now,
@@ -616929,7 +617548,7 @@ function registerDaydreamOpportunities(state, opportunities, now = Date.now()) {
616929
617548
  };
616930
617549
  if (existing) {
616931
617550
  item.trigger = compact2(opportunity.trigger, 240) || item.trigger;
616932
- item.confidence = clamp019(opportunity.confidence);
617551
+ item.confidence = clamp0110(opportunity.confidence);
616933
617552
  item.updatedAt = now;
616934
617553
  }
616935
617554
  state.daydreamOpportunities[id] = item;
@@ -617069,8 +617688,8 @@ function upsertRelationship(state, kind, fromKey, toKey, messageId, confidence2,
617069
617688
  evidenceMessageIds: [],
617070
617689
  source
617071
617690
  };
617072
- edge.confidence = Math.max(edge.confidence, clamp019(confidence2));
617073
- edge.weight = Math.min(1, edge.weight + 0.12 + clamp019(confidence2) * 0.2);
617691
+ edge.confidence = Math.max(edge.confidence, clamp0110(confidence2));
617692
+ edge.weight = Math.min(1, edge.weight + 0.12 + clamp0110(confidence2) * 0.2);
617074
617693
  edge.lastSeenAt = now;
617075
617694
  edge.evidenceMessageIds = appendUnique(edge.evidenceMessageIds, messageId, 40);
617076
617695
  edge.note = compactOptional(note, 260) || edge.note;
@@ -617112,7 +617731,7 @@ function setPreference(vector, key, value2, confidence2, messageId, now, note) {
617112
617731
  const existing = vector[key];
617113
617732
  vector[key] = {
617114
617733
  value: existing ? existing.value * 0.7 + value2 * 0.3 : value2,
617115
- confidence: Math.max(existing?.confidence ?? 0, clamp019(confidence2)),
617734
+ confidence: Math.max(existing?.confidence ?? 0, clamp0110(confidence2)),
617116
617735
  updatedAt: now,
617117
617736
  evidenceMessageIds: appendUnique(existing?.evidenceMessageIds ?? [], messageId, 12),
617118
617737
  note
@@ -617503,9 +618122,31 @@ function parseTelegramSilentReflectionNotes(text) {
617503
618122
  }
617504
618123
  return null;
617505
618124
  }
617506
- function telegramRouterTimeoutMs(configTimeoutMs, minMs = 12e4, _legacyMaxMs) {
617507
- const configured = Number.isFinite(configTimeoutMs) && (configTimeoutMs ?? 0) > 0 ? configTimeoutMs : 3e5;
617508
- return Math.max(configured, minMs, 12e4);
618125
+ function estimatePromptTokensFromRequest(request) {
618126
+ let chars = 0;
618127
+ for (const m2 of request.messages ?? []) {
618128
+ if (typeof m2.content === "string") chars += m2.content.length;
618129
+ else if (Array.isArray(m2.content)) {
618130
+ for (const part of m2.content) {
618131
+ if (typeof part?.text === "string") chars += part.text.length;
618132
+ }
618133
+ }
618134
+ chars += 8;
618135
+ }
618136
+ if (Array.isArray(request.tools) && request.tools.length > 0) {
618137
+ chars += request.tools.length * 600;
618138
+ }
618139
+ return Math.ceil(chars / 4);
618140
+ }
618141
+ function telegramRouterTimeoutMs(configTimeoutMs, _minMs, _legacyMaxMs) {
618142
+ void _minMs;
618143
+ void _legacyMaxMs;
618144
+ const envRaw = Number.parseInt(process.env["OMNIUS_TG_INFERENCE_LIVENESS_MS"] ?? "", 10);
618145
+ const livenessMs = Number.isFinite(envRaw) && envRaw >= 1e4 ? envRaw : 6e5;
618146
+ if (Number.isFinite(configTimeoutMs) && (configTimeoutMs ?? 0) >= livenessMs) {
618147
+ return configTimeoutMs;
618148
+ }
618149
+ return livenessMs;
617509
618150
  }
617510
618151
  function telegramThinkSuppressedRequest(request) {
617511
618152
  const messages2 = Array.isArray(request.messages) ? request.messages.slice() : [];
@@ -618960,6 +619601,9 @@ var init_telegram_bridge = __esm({
618960
619601
  init_telegram_creative_tools();
618961
619602
  init_omnius_directory();
618962
619603
  init_stimulation();
619604
+ init_pid_controller();
619605
+ init_component_benefit();
619606
+ init_soul_observations();
618963
619607
  init_identity_memory_tool();
618964
619608
  init_visual_identity_association();
618965
619609
  init_telegram_channel_dmn();
@@ -622925,6 +623569,12 @@ ${lines.join("\n")}`);
622925
623569
  this.ensureTelegramConversationLoaded(sessionKey);
622926
623570
  const history = this.chatHistory.get(sessionKey) ?? [];
622927
623571
  const participants = [...this.chatParticipants.get(sessionKey)?.values() ?? []].sort((a2, b) => b.lastSeenTs - a2.lastSeenTs);
623572
+ const modelKey = this.agentConfig?.model ?? "?";
623573
+ const pidReg = getPidRegistry();
623574
+ const tier1Ratio = pidReg.output(`tier1.${modelKey}`);
623575
+ const tier2Ratio = pidReg.output(`tier2.${modelKey}`);
623576
+ const benefitReg = getComponentBenefitRegistry();
623577
+ const sampledComponents = [];
622928
623578
  const isGroup = msg.chatType !== "private";
622929
623579
  const retainedCount = history.length;
622930
623580
  const olderCount = Math.max(0, retainedCount - maxRecent);
@@ -622958,14 +623608,28 @@ ${lines.join("\n")}`);
622958
623608
  sections.push(socialStateContext);
622959
623609
  }
622960
623610
  if (participants.length > 0) {
622961
- const participantLines = participants.slice(0, 12).map((profile) => {
623611
+ const fullCount = Math.min(12, participants.length);
623612
+ const tier1Count = Math.max(1, Math.round(fullCount * tier1Ratio));
623613
+ const sortedByBenefit = participants.slice(0, fullCount).sort((a2, b) => {
623614
+ const scoreA = benefitReg.score(sessionKey, `tier1.participant.${a2.username ?? a2.fromUserId}`);
623615
+ const scoreB = benefitReg.score(sessionKey, `tier1.participant.${b.username ?? b.fromUserId}`);
623616
+ return scoreB - scoreA;
623617
+ });
623618
+ const selected = sortedByBenefit.slice(0, tier1Count);
623619
+ const participantLines = selected.map((profile) => {
622962
623620
  const label = profile.username && profile.username !== "unknown" ? `@${profile.username}` : profile.firstName || `user:${profile.fromUserId}`;
622963
623621
  const tones = [...profile.toneTags].slice(0, 5).join(", ") || "neutral";
622964
623622
  const direct = profile.directAddressCount ? `, direct-addresses:${profile.directAddressCount}` : "";
622965
623623
  const replies = profile.replyCount ? `, replies:${profile.replyCount}` : "";
623624
+ sampledComponents.push({
623625
+ key: `tier1.participant.${profile.username ?? profile.fromUserId}`,
623626
+ needle: profile.username ?? String(profile.fromUserId)
623627
+ });
622966
623628
  return `- ${label} [${telegramActorKindLabel(profile)}]: messages:${profile.messageCount}${direct}${replies}; tone:${tones}; last=${telegramContextJsonString(profile.lastMessage, 180)}`;
622967
623629
  });
622968
- sections.push(`### Participants And Relationship Signals
623630
+ const shed = fullCount - tier1Count;
623631
+ const tierNote = shed > 0 ? ` (tier1 u=${tier1Ratio.toFixed(2)}; ${shed} participants shed by benefit)` : "";
623632
+ sections.push(`### Participants And Relationship Signals${tierNote}
622969
623633
  ${participantLines.join("\n")}`);
622970
623634
  }
622971
623635
  const associativeContext = this.relevantTelegramAssociativeMemoryContext(
@@ -622997,16 +623661,32 @@ ${participantLines.join("\n")}`);
622997
623661
  }
622998
623662
  const memoryCards = this.relevantTelegramMemoryCards(sessionKey, msg, isGroup ? 10 : 6);
622999
623663
  if (memoryCards.length > 0) {
623000
- const cardLines = memoryCards.map(({ card, score }) => {
623001
- const tags = card.tags.length ? ` tags:${card.tags.slice(0, 8).join(",")}` : "";
623002
- const speakers = card.speakers.length ? ` speakers:${card.speakers.join(", ")}` : "";
623003
- const relevance = score > 0 ? ` relevance:${score.toFixed(2)}` : " relevance:recent";
623004
- const notes2 = card.notes.slice(-3).map((note) => ` - note=${telegramContextJsonString(note, 220)}`).join("\n");
623005
- return `- ${card.title} (${card.id};${relevance};${speakers}${tags})
623664
+ const fullMC = memoryCards.length;
623665
+ const tier2Count = Math.max(0, Math.round(fullMC * tier2Ratio));
623666
+ const sortedMC = [...memoryCards].sort((a2, b) => {
623667
+ const scoreA = benefitReg.score(sessionKey, `tier2.memory_card.${a2.card.id}`);
623668
+ const scoreB = benefitReg.score(sessionKey, `tier2.memory_card.${b.card.id}`);
623669
+ return scoreB - scoreA;
623670
+ });
623671
+ const selectedMC = sortedMC.slice(0, tier2Count);
623672
+ if (selectedMC.length > 0) {
623673
+ const cardLines = selectedMC.map(({ card, score }) => {
623674
+ const tags = card.tags.length ? ` tags:${card.tags.slice(0, 8).join(",")}` : "";
623675
+ const speakers = card.speakers.length ? ` speakers:${card.speakers.join(", ")}` : "";
623676
+ const relevance = score > 0 ? ` relevance:${score.toFixed(2)}` : " relevance:recent";
623677
+ const notes2 = card.notes.slice(-3).map((note) => ` - note=${telegramContextJsonString(note, 220)}`).join("\n");
623678
+ sampledComponents.push({
623679
+ key: `tier2.memory_card.${card.id}`,
623680
+ needle: card.id
623681
+ });
623682
+ return `- ${card.title} (${card.id};${relevance};${speakers}${tags})
623006
623683
  ${notes2}`;
623007
- });
623008
- sections.push(`### Zettelkasten Memory Recall (untrusted conversation notes)
623684
+ });
623685
+ const shed = fullMC - tier2Count;
623686
+ const tierNote = shed > 0 ? ` (tier2 u=${tier2Ratio.toFixed(2)}; ${shed} cards shed by benefit)` : "";
623687
+ sections.push(`### Zettelkasten Memory Recall (untrusted conversation notes)${tierNote}
623009
623688
  ${cardLines.join("\n")}`);
623689
+ }
623010
623690
  }
623011
623691
  const channelDaydream = this.formatLatestTelegramChannelDaydreamContext(sessionKey);
623012
623692
  if (channelDaydream) {
@@ -623079,6 +623759,7 @@ ${lines.join("\n")}`);
623079
623759
  `- If the current sender asks what you see or remember, answer from this stream instead of saying the history is gone.`
623080
623760
  ].join("\n")
623081
623761
  );
623762
+ this.telegramStashContextSamples(sessionKey, sampledComponents);
623082
623763
  return sections.join("\n\n");
623083
623764
  }
623084
623765
  maybeLogTelegramGroupSkip(msg, reason) {
@@ -623141,6 +623822,25 @@ ${lines.join("\n")}`);
623141
623822
  nextAnalysisAfterMessages: decision2.nextCheckAfterMessages
623142
623823
  });
623143
623824
  }
623825
+ /**
623826
+ * Collect the per-component benefit samples that were tagged when assembling
623827
+ * the last context stream for this session. Returns the same shape the
623828
+ * component-benefit registry consumes; an empty list means no tier-1/tier-2
623829
+ * components were emitted (early return — benefit tracking skipped).
623830
+ *
623831
+ * Tags are stored on `_telegramLastContextSamples` (a per-session WeakMap-
623832
+ * style cache) so the post-call feedback knows what to score without
623833
+ * re-running the context assembly.
623834
+ */
623835
+ telegramComponentSamplesForSession(sessionKey) {
623836
+ return this._telegramLastContextSamples.get(sessionKey) ?? [];
623837
+ }
623838
+ /** Per-session cache of last emitted context-component samples. */
623839
+ _telegramLastContextSamples = /* @__PURE__ */ new Map();
623840
+ /** Stash samples for the next post-call feedback cycle. */
623841
+ telegramStashContextSamples(sessionKey, samples) {
623842
+ this._telegramLastContextSamples.set(sessionKey, samples);
623843
+ }
623144
623844
  buildTelegramRouterPersonaContext(sessionKey, msg, toolContext, selfIdentityContext) {
623145
623845
  const baseContract = toolContext === "telegram-admin-dm" ? ADMIN_DM_PROMPT : toolContext === "telegram-admin-group" ? ADMIN_GROUP_PROMPT : TELEGRAM_SAFETY_PROMPT;
623146
623846
  return buildSoulContext({
@@ -623335,30 +624035,55 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`,
623335
624035
  * hard-deadline retire path becomes diagnosable instead of opaque
623336
624036
  */
623337
624037
  async telegramObservableInference(backend, request, kind, sessionKey) {
624038
+ const model = this.agentConfig?.model ?? "?";
624039
+ const promptTokens = estimatePromptTokensFromRequest(request);
624040
+ const broker = getModelBroker();
624041
+ const trainCtx = await broker.getNctxTrain(model).catch(() => null);
624042
+ const targetCtx = trainCtx && trainCtx > 0 ? Math.min(trainCtx, Math.max(2048, promptTokens + 1024)) : Math.max(2048, promptTokens + 1024);
624043
+ const requestWithCtx = { ...request, numCtx: targetCtx };
624044
+ const slot = await broker.acquireInferenceSlot({
624045
+ model,
624046
+ domain: "chat",
624047
+ owner: `telegram-bridge/${kind}`,
624048
+ sessionKey,
624049
+ promptTokens,
624050
+ priority: kind === "router" || kind === "router-repair" || kind === "router-strict-retry" ? 1 : 0
624051
+ });
624052
+ this.tuiWrite(() => renderTelegramSubAgentEvent(
624053
+ sessionKey,
624054
+ `inference admitted [${kind}] model=${model} prompt~${promptTokens}t num_ctx=${targetCtx} slot=${slot.info.id}${slot.info.reserved ? " reserved" : ""}`
624055
+ ));
623338
624056
  const streamFn = backend.chatCompletionStream;
623339
- const id = this.registerTelegramInference(kind, sessionKey, this.agentConfig?.model ?? "?");
624057
+ const id = this.registerTelegramInference(kind, sessionKey, model);
624058
+ let completionTokens = 0;
623340
624059
  try {
624060
+ let result;
623341
624061
  if (typeof streamFn !== "function") {
623342
- const r2 = await backend.chatCompletion(request);
623343
- this.updateTelegramInferenceFinal(id, r2);
623344
- return r2;
623345
- }
623346
- try {
623347
- const result = await this.streamTelegramInferenceToCompletion(
623348
- streamFn.bind(backend),
623349
- request,
623350
- id
623351
- );
623352
- return result;
623353
- } catch (streamErr) {
623354
- const r2 = await backend.chatCompletion(request);
623355
- this.updateTelegramInferenceFinal(id, r2);
623356
- this.tuiWrite(() => renderTelegramSubAgentEvent(
623357
- sessionKey,
623358
- `inference ${id}: stream errored (${streamErr instanceof Error ? streamErr.message : String(streamErr)}); fell back to non-stream`
623359
- ));
623360
- return r2;
624062
+ result = await backend.chatCompletion(requestWithCtx);
624063
+ this.updateTelegramInferenceFinal(id, result);
624064
+ } else {
624065
+ try {
624066
+ result = await this.streamTelegramInferenceToCompletion(
624067
+ streamFn.bind(backend),
624068
+ requestWithCtx,
624069
+ id
624070
+ );
624071
+ } catch (streamErr) {
624072
+ result = await backend.chatCompletion(requestWithCtx);
624073
+ this.updateTelegramInferenceFinal(id, result);
624074
+ this.tuiWrite(() => renderTelegramSubAgentEvent(
624075
+ sessionKey,
624076
+ `inference ${id}: stream errored (${streamErr instanceof Error ? streamErr.message : String(streamErr)}); fell back to non-stream`
624077
+ ));
624078
+ }
623361
624079
  }
624080
+ const usage = result.usage;
624081
+ completionTokens = usage?.completion_tokens ?? 0;
624082
+ slot.release({ ok: true, completionTokens });
624083
+ return result;
624084
+ } catch (err) {
624085
+ slot.release({ ok: false, error: err instanceof Error ? err.message : String(err) });
624086
+ throw err;
623362
624087
  } finally {
623363
624088
  this.deregisterTelegramInference(id);
623364
624089
  }
@@ -623718,33 +624443,15 @@ ${retryText}`,
623718
624443
  /**
623719
624444
  * Internal: start an actual router inference for a sessionKey, store its
623720
624445
  * in-flight promise, and on completion fire any queued trailing call.
624446
+ *
624447
+ * No watchdog timeout — the broker's admission control guarantees the
624448
+ * inference fits available compute. Inflight work always completes; new
624449
+ * work waits in the broker's bounded queue with backpressure to upstream.
624450
+ * Only the fetch-level I/O liveness AbortSignal can interrupt, and only
624451
+ * on TCP-dead.
623721
624452
  */
623722
624453
  startCoalescedTelegramRouterCall(sessionKey, msg, toolContext) {
623723
- const HARD_DEADLINE_MS = this.telegramRouterHardDeadlineMs();
623724
- const inner = this.inferTelegramInteractionDecision(msg, toolContext);
623725
- const promise = new Promise((resolve55, reject) => {
623726
- let settled = false;
623727
- const guard = setTimeout(() => {
623728
- if (settled) return;
623729
- settled = true;
623730
- reject(new Error(`router-coalescer: hard deadline exceeded (${Math.round(HARD_DEADLINE_MS / 1e3)}s); inner inference did not settle`));
623731
- }, HARD_DEADLINE_MS);
623732
- if (typeof guard.unref === "function") guard.unref();
623733
- inner.then(
623734
- (v) => {
623735
- if (settled) return;
623736
- settled = true;
623737
- clearTimeout(guard);
623738
- resolve55(v);
623739
- },
623740
- (e2) => {
623741
- if (settled) return;
623742
- settled = true;
623743
- clearTimeout(guard);
623744
- reject(e2);
623745
- }
623746
- );
623747
- });
624454
+ const promise = this.inferTelegramInteractionDecision(msg, toolContext);
623748
624455
  this.telegramRouterSessionState.set(sessionKey, { inFlight: promise });
623749
624456
  const onSettled = () => {
623750
624457
  let state;
@@ -623765,11 +624472,6 @@ ${retryText}`,
623765
624472
  promise.then(onSettled, onSettled);
623766
624473
  return promise;
623767
624474
  }
623768
- telegramRouterHardDeadlineMs() {
623769
- const raw = Number.parseInt(process.env["OMNIUS_TG_ROUTER_HARD_DEADLINE_MS"] ?? "", 10);
623770
- if (Number.isFinite(raw) && raw >= 5e3 && raw <= 18e4) return raw;
623771
- return 6e4;
623772
- }
623773
624475
  /**
623774
624476
  * Forcibly cancel every in-flight + trailing router-coalescer entry.
623775
624477
  * Used on bridge stop() and by the watchdog if it detects the coalescer
@@ -623965,30 +624667,52 @@ ${stimulationProbe.context}`,
623965
624667
  "",
623966
624668
  context2
623967
624669
  ].filter(Boolean).join("\n");
623968
- const reflectionNotes = await this.inferTelegramSilentReflectionNotes(
623969
- backend,
623970
- sessionKey,
623971
- msg,
623972
- toolContext,
623973
- personaContext,
623974
- observationContext,
623975
- config.timeoutMs
623976
- );
623977
- const reflectionContext = [
623978
- "## Silent Reflection Deliverables (must inform the attention decision)",
623979
- `silent_disposition: ${reflectionNotes.silentDisposition ?? "heard and retained"}`,
623980
- `mental_note: ${reflectionNotes.mentalNote ?? "no additional observation"}`,
623981
- `memory_note: ${reflectionNotes.memoryNote ?? "message retained in scoped memory"}`,
623982
- `relationship_note: ${reflectionNotes.relationshipNote ?? "no relationship change inferred"}`,
623983
- `procedure_note: ${reflectionNotes.procedureNote ?? "active voice-soul tree loaded; no procedure change inferred"}`,
623984
- `voice_note: ${reflectionNotes.voiceNote ?? "final voice unchanged unless reply is emitted"}`,
623985
- `scenario_note: ${reflectionNotes.scenarioNote ?? "scenario classification unavailable"}`,
623986
- `scenario_id: ${reflectionNotes.scenarioId ?? "unclassified"}`,
623987
- `scenario_label: ${reflectionNotes.scenarioLabel ?? "Unclassified"}`,
623988
- `scenario_confidence: ${reflectionNotes.scenarioConfidence !== void 0 ? reflectionNotes.scenarioConfidence.toFixed(2) : "0.00"}`,
623989
- `scenario_objective: ${reflectionNotes.scenarioObjective ?? "pending model-derived classifier output"}`,
623990
- `scenario_state_loop: ${reflectionNotes.scenarioStateLoop ?? "pending model-derived classifier output"}`
623991
- ].join("\n");
624670
+ const brokerSnap = getModelBroker().snapshot();
624671
+ const idleSlotRatio = brokerSnap.slots.capacity > 0 ? 1 - brokerSnap.slots.inUse / brokerSnap.slots.capacity : 1;
624672
+ const consolidatedMode = idleSlotRatio < 0.5 || process.env["OMNIUS_TG_FORCE_CONSOLIDATED"] === "1";
624673
+ let reflectionNotes;
624674
+ let reflectionContext;
624675
+ if (consolidatedMode) {
624676
+ reflectionNotes = this.fallbackTelegramSilentReflectionNotes(msg, "consolidated mode: reflection computed inline by router");
624677
+ reflectionContext = [
624678
+ "## Consolidated Reflection (you produce these fields as part of the same JSON)",
624679
+ "Before emitting your final decision, internally reflect on:",
624680
+ " silent_disposition: what happens silently with this message",
624681
+ " mental_note: concise observation of the turn",
624682
+ " memory_note: what scoped memory should retain or connect",
624683
+ " relationship_note: relationship/thread implication",
624684
+ " procedure_note: active tree/branch/abort implication",
624685
+ " voice_note: final voice implication if a reply happens",
624686
+ " scenario_note: identified scenario and transition state",
624687
+ " scenario_id / scenario_label / scenario_confidence / scenario_objective / scenario_state_loop",
624688
+ "Use these as your attention substrate, then decide route/should_reply/confidence. Return all fields in ONE JSON."
624689
+ ].join("\n");
624690
+ } else {
624691
+ reflectionNotes = await this.inferTelegramSilentReflectionNotes(
624692
+ backend,
624693
+ sessionKey,
624694
+ msg,
624695
+ toolContext,
624696
+ personaContext,
624697
+ observationContext,
624698
+ config.timeoutMs
624699
+ );
624700
+ reflectionContext = [
624701
+ "## Silent Reflection Deliverables (must inform the attention decision)",
624702
+ `silent_disposition: ${reflectionNotes.silentDisposition ?? "heard and retained"}`,
624703
+ `mental_note: ${reflectionNotes.mentalNote ?? "no additional observation"}`,
624704
+ `memory_note: ${reflectionNotes.memoryNote ?? "message retained in scoped memory"}`,
624705
+ `relationship_note: ${reflectionNotes.relationshipNote ?? "no relationship change inferred"}`,
624706
+ `procedure_note: ${reflectionNotes.procedureNote ?? "active voice-soul tree loaded; no procedure change inferred"}`,
624707
+ `voice_note: ${reflectionNotes.voiceNote ?? "final voice unchanged unless reply is emitted"}`,
624708
+ `scenario_note: ${reflectionNotes.scenarioNote ?? "scenario classification unavailable"}`,
624709
+ `scenario_id: ${reflectionNotes.scenarioId ?? "unclassified"}`,
624710
+ `scenario_label: ${reflectionNotes.scenarioLabel ?? "Unclassified"}`,
624711
+ `scenario_confidence: ${reflectionNotes.scenarioConfidence !== void 0 ? reflectionNotes.scenarioConfidence.toFixed(2) : "0.00"}`,
624712
+ `scenario_objective: ${reflectionNotes.scenarioObjective ?? "pending model-derived classifier output"}`,
624713
+ `scenario_state_loop: ${reflectionNotes.scenarioStateLoop ?? "pending model-derived classifier output"}`
624714
+ ].join("\n");
624715
+ }
623992
624716
  const userPrompt = [
623993
624717
  `You are the Telegram live routing and reply-discretion model.`,
623994
624718
  `The attention decision must happen after reading the silent reflection deliverables below. The notes are not decorations: they are the decision substrate.`,
@@ -624020,10 +624744,13 @@ ${stimulationProbe.context}`,
624020
624744
  ``,
624021
624745
  observationContext,
624022
624746
  ``,
624747
+ formatSystemObservations(sessionKey),
624748
+ ``,
624023
624749
  `Current Telegram message text (untrusted user data):
624024
624750
  ${this.quoteTelegramContextBlock(msg.text, 1200)}`
624025
624751
  ].filter(Boolean).join("\n");
624026
624752
  const diagnostics = {};
624753
+ const routerStartMs = Date.now();
624027
624754
  try {
624028
624755
  const result = await this.telegramRouterJsonCompletion(backend, {
624029
624756
  messages: [
@@ -624040,6 +624767,21 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`
624040
624767
  think: false
624041
624768
  }, diagnostics);
624042
624769
  const text = result.choices[0]?.message?.content ?? "";
624770
+ const routerLatencyMs = Date.now() - routerStartMs;
624771
+ try {
624772
+ const pidReg = getPidRegistry();
624773
+ const modelKey = this.agentConfig?.model ?? "?";
624774
+ pidReg.sample(`tier1.${modelKey}`, routerLatencyMs);
624775
+ pidReg.sample(`tier2.${modelKey}`, routerLatencyMs);
624776
+ } catch {
624777
+ }
624778
+ try {
624779
+ const samples = this.telegramComponentSamplesForSession(sessionKey);
624780
+ if (samples.length > 0) {
624781
+ getComponentBenefitRegistry().recordOutcome(sessionKey, samples, text);
624782
+ }
624783
+ } catch {
624784
+ }
624043
624785
  const parsed = parseTelegramInteractionDecision(text, forcedRoute, {
624044
624786
  defaultShouldReply: false
624045
624787
  });
@@ -628274,11 +629016,18 @@ ${text}`.trim());
628274
629016
  };
628275
629017
  const replyParameters = idx === 0 ? telegramReplyParameters(replyToMessageId) : void 0;
628276
629018
  if (replyParameters) body["reply_parameters"] = replyParameters;
629019
+ const sessionKeyForObs = String(chatId);
628277
629020
  try {
628278
629021
  const result = await this.apiCall("sendMessage", body);
628279
629022
  if (result.ok === false) throw new Error(String(result.description || "Telegram sendMessage failed"));
628280
629023
  this.state.messagesSent++;
628281
629024
  if (sentId === null) sentId = result.result?.message_id ?? null;
629025
+ getSoulObservationStream().emit({
629026
+ kind: "telegram.send.success",
629027
+ sessionKey: sessionKeyForObs,
629028
+ messageId: result.result?.message_id ?? void 0,
629029
+ ts: Date.now()
629030
+ });
628282
629031
  } catch {
628283
629032
  const plain = chunk.replace(/<[^>]+>/g, "");
628284
629033
  const fallbackBody = { chat_id: chatId, text: plain };
@@ -628288,8 +629037,32 @@ ${text}`.trim());
628288
629037
  if (result.ok === false) throw new Error(String(result.description || "Telegram sendMessage failed"));
628289
629038
  this.state.messagesSent++;
628290
629039
  if (sentId === null) sentId = result.result?.message_id ?? null;
629040
+ getSoulObservationStream().emit({
629041
+ kind: "telegram.send.success",
629042
+ sessionKey: sessionKeyForObs,
629043
+ messageId: result.result?.message_id ?? void 0,
629044
+ ts: Date.now()
629045
+ });
628291
629046
  } catch (err) {
628292
629047
  this.tuiWrite(() => renderWarning(`Failed to send Telegram message: ${err instanceof Error ? err.message : String(err)}`));
629048
+ const errStr = err instanceof Error ? err.message : String(err);
629049
+ const lc = errStr.toLowerCase();
629050
+ if (/(not enough rights|forbidden|chat_write_forbidden|user_banned|kicked|chat_admin_required)/.test(lc)) {
629051
+ getSoulObservationStream().emit({
629052
+ kind: "telegram.send.forbidden",
629053
+ sessionKey: sessionKeyForObs,
629054
+ reason: errStr,
629055
+ ts: Date.now()
629056
+ });
629057
+ } else if (/too many requests|retry after/.test(lc)) {
629058
+ const m2 = lc.match(/retry after (\d+)/);
629059
+ getSoulObservationStream().emit({
629060
+ kind: "telegram.send.rate_limited",
629061
+ sessionKey: sessionKeyForObs,
629062
+ retryAfterSec: m2 ? parseInt(m2[1], 10) : void 0,
629063
+ ts: Date.now()
629064
+ });
629065
+ }
628293
629066
  }
628294
629067
  }
628295
629068
  }
@@ -630726,7 +631499,7 @@ __export(voicechat_exports, {
630726
631499
  VoiceChatSession: () => VoiceChatSession
630727
631500
  });
630728
631501
  import { EventEmitter as EventEmitter13 } from "node:events";
630729
- function clamp0110(x) {
631502
+ function clamp0111(x) {
630730
631503
  return x < 0 ? 0 : x > 1 ? 1 : x;
630731
631504
  }
630732
631505
  function alnumRatio(s2) {
@@ -630765,9 +631538,9 @@ function computeSignalFromText(text, confidence2) {
630765
631538
  else score = 0.15;
630766
631539
  score -= repeatingCharPenalty(t2) * 0.4;
630767
631540
  if (typeof confidence2 === "number" && !Number.isNaN(confidence2)) {
630768
- score = 0.7 * score + 0.3 * clamp0110(confidence2);
631541
+ score = 0.7 * score + 0.3 * clamp0111(confidence2);
630769
631542
  }
630770
- return clamp0110(score);
631543
+ return clamp0111(score);
630771
631544
  }
630772
631545
  function truncateForLog(s2, n2) {
630773
631546
  return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "…";
@@ -631037,7 +631810,7 @@ Rules:
631037
631810
  }, MAX_SEGMENT_MS);
631038
631811
  }
631039
631812
  this.captureBuffer = text;
631040
- this.lastSignalScore = typeof snr === "number" && !Number.isNaN(snr) ? clamp0110(snr) : computeSignalFromText(text, confidence2);
631813
+ this.lastSignalScore = typeof snr === "number" && !Number.isNaN(snr) ? clamp0111(snr) : computeSignalFromText(text, confidence2);
631041
631814
  this.emit("snr", { score: this.lastSignalScore });
631042
631815
  this.onPartialTranscript(text);
631043
631816
  if (this.silenceTimer) clearTimeout(this.silenceTimer);