omnius 1.0.439 → 1.0.441

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
@@ -603827,6 +603827,56 @@ function updateListenLiveState(patch) {
603827
603827
  function getListenLiveState() {
603828
603828
  return listenLiveState;
603829
603829
  }
603830
+ function clamp0110(value2) {
603831
+ if (!Number.isFinite(value2)) return 0;
603832
+ return Math.max(0, Math.min(1, value2));
603833
+ }
603834
+ function micColor(text2, level) {
603835
+ const idx = Math.round(clamp0110(level) * (MIC_GRADIENT_256.length - 1));
603836
+ const code8 = MIC_GRADIENT_256[idx] ?? 21;
603837
+ return `\x1B[38;5;${code8}m${text2}\x1B[0m`;
603838
+ }
603839
+ function micLevelChar(level) {
603840
+ const idx = Math.round(clamp0110(level) * (MIC_LEVEL_CHARS.length - 1));
603841
+ return MIC_LEVEL_CHARS[idx] ?? "▁";
603842
+ }
603843
+ function micSpectrumChar(level) {
603844
+ const idx = Math.round(clamp0110(level) * (MIC_SPECTRUM_CHARS.length - 1));
603845
+ return MIC_SPECTRUM_CHARS[idx] ?? " ";
603846
+ }
603847
+ function renderMicWaveform(bucketSquares, bucketCounts, peak) {
603848
+ return bucketSquares.map((sum, idx) => {
603849
+ const count = Math.max(1, bucketCounts[idx] ?? 1);
603850
+ const level = Math.sqrt(sum / count);
603851
+ const normalized = clamp0110(level / Math.max(0.02, peak || 0.02));
603852
+ return micColor(micLevelChar(normalized), normalized);
603853
+ }).join("");
603854
+ }
603855
+ function renderMicSpectrum(samples) {
603856
+ if (samples.length < 16) return "";
603857
+ const n2 = Math.min(256, samples.length);
603858
+ const src2 = samples.slice(0, n2);
603859
+ const bands = [];
603860
+ const maxK = Math.max(2, Math.floor(n2 / 2) - 1);
603861
+ for (let band = 0; band < MIC_SPECTRUM_BANDS; band++) {
603862
+ const t2 = MIC_SPECTRUM_BANDS <= 1 ? 0 : band / (MIC_SPECTRUM_BANDS - 1);
603863
+ const k = Math.max(1, Math.min(maxK, Math.round(1 + (Math.exp(t2 * Math.log(maxK)) - 1))));
603864
+ let re = 0;
603865
+ let im = 0;
603866
+ for (let i2 = 0; i2 < n2; i2++) {
603867
+ const w = 0.5 - 0.5 * Math.cos(2 * Math.PI * i2 / Math.max(1, n2 - 1));
603868
+ const angle = 2 * Math.PI * k * i2 / n2;
603869
+ const sample = (src2[i2] ?? 0) * w;
603870
+ re += sample * Math.cos(angle);
603871
+ im -= sample * Math.sin(angle);
603872
+ }
603873
+ const mag = Math.sqrt(re * re + im * im) / n2;
603874
+ const db = 20 * Math.log10(Math.max(1e-7, mag));
603875
+ const normalized = clamp0110((db + 75) / 75);
603876
+ bands.push(micColor(micSpectrumChar(normalized), normalized));
603877
+ }
603878
+ return bands.join("");
603879
+ }
603830
603880
  async function resolveMicSource() {
603831
603881
  const configured = String(process.env["OMNIUS_MIC_DEVICE"] ?? "").trim();
603832
603882
  if (configured.startsWith("hw:") || configured.startsWith("plughw:")) {
@@ -604265,7 +604315,7 @@ function getListenEngine(config) {
604265
604315
  }
604266
604316
  return _engine;
604267
604317
  }
604268
- var MANAGED_TRANSCRIBE_CLI_DIR2, AUDIO_EXTENSIONS, VIDEO_EXTENSIONS2, listenLiveState, lastHardwareVadAt, WhisperFallbackTranscriber, ListenEngine, _bgInstallPromise, _managedTranscribeCliInstallPromise, _engine;
604318
+ var MANAGED_TRANSCRIBE_CLI_DIR2, AUDIO_EXTENSIONS, VIDEO_EXTENSIONS2, listenLiveState, lastHardwareVadAt, MIC_WAVEFORM_BINS, MIC_SPECTRUM_BANDS, MIC_WATERFALL_ROWS, MIC_LEVEL_CHARS, MIC_SPECTRUM_CHARS, MIC_GRADIENT_256, WhisperFallbackTranscriber, ListenEngine, _bgInstallPromise, _managedTranscribeCliInstallPromise, _engine;
604269
604319
  var init_listen = __esm({
604270
604320
  "packages/cli/src/tui/listen.ts"() {
604271
604321
  "use strict";
@@ -604302,6 +604352,9 @@ var init_listen = __esm({
604302
604352
  micLevelDb: null,
604303
604353
  noiseFloorDb: null,
604304
604354
  speechActive: false,
604355
+ waveform: "",
604356
+ spectrum: "",
604357
+ waterfall: [],
604305
604358
  doa: null,
604306
604359
  lastTranscript: "",
604307
604360
  lastTranscriptAt: 0,
@@ -604311,6 +604364,33 @@ var init_listen = __esm({
604311
604364
  updatedAt: 0
604312
604365
  };
604313
604366
  lastHardwareVadAt = 0;
604367
+ MIC_WAVEFORM_BINS = 56;
604368
+ MIC_SPECTRUM_BANDS = 28;
604369
+ MIC_WATERFALL_ROWS = 8;
604370
+ MIC_LEVEL_CHARS = "▁▂▃▄▅▆▇█";
604371
+ MIC_SPECTRUM_CHARS = " .:-=+*#%@";
604372
+ MIC_GRADIENT_256 = [
604373
+ 21,
604374
+ 27,
604375
+ 33,
604376
+ 39,
604377
+ 45,
604378
+ 51,
604379
+ 50,
604380
+ 49,
604381
+ 48,
604382
+ 47,
604383
+ 82,
604384
+ 118,
604385
+ 154,
604386
+ 190,
604387
+ 226,
604388
+ 220,
604389
+ 214,
604390
+ 208,
604391
+ 202,
604392
+ 196
604393
+ ];
604314
604394
  WhisperFallbackTranscriber = class extends EventEmitter6 {
604315
604395
  constructor(model, scriptPath2) {
604316
604396
  super();
@@ -604322,6 +604402,8 @@ var init_listen = __esm({
604322
604402
  process = null;
604323
604403
  _ready = false;
604324
604404
  registeredBrokerName = null;
604405
+ lastVadSpeech = null;
604406
+ lastVisibleVadAt = 0;
604325
604407
  get ready() {
604326
604408
  return this._ready;
604327
604409
  }
@@ -604355,7 +604437,7 @@ var init_listen = __esm({
604355
604437
  const consensusEnv = String(process.env["OMNIUS_ASR_CONSENSUS"] ?? "").trim().toLowerCase();
604356
604438
  const consensusModel = consensusEnv === "0" || consensusEnv === "off" || consensusEnv === "false" ? "off" : consensusEnv || defaultConsensusModel(this.model);
604357
604439
  const consensusThreshold = String(process.env["OMNIUS_ASR_CONSENSUS_THRESHOLD"] ?? "0.45");
604358
- const silenceMs = String(process.env["OMNIUS_ASR_SILENCE_MS"] ?? "800");
604440
+ const silenceMs = String(process.env["OMNIUS_ASR_SILENCE_MS"] ?? "3000");
604359
604441
  this.process = spawn29(
604360
604442
  pyPath,
604361
604443
  [
@@ -604423,9 +604505,15 @@ var init_listen = __esm({
604423
604505
  case "vad": {
604424
604506
  lastHardwareVadAt = Date.now();
604425
604507
  const doa = Number(evt.doa);
604426
- this.emit("status", `Whisper VAD: ${evt.speech === true ? "speech" : "silence"}`);
604508
+ const speech = evt.speech === true;
604509
+ const now2 = Date.now();
604510
+ if (process.env["OMNIUS_ASR_VERBOSE_VAD"] === "1" && (speech !== this.lastVadSpeech || now2 - this.lastVisibleVadAt > 1e4)) {
604511
+ this.emit("status", `Whisper VAD: ${speech ? "speech" : "silence"}`);
604512
+ this.lastVisibleVadAt = now2;
604513
+ }
604514
+ this.lastVadSpeech = speech;
604427
604515
  updateListenLiveState({
604428
- speechActive: evt.speech === true,
604516
+ speechActive: speech,
604429
604517
  doa: Number.isFinite(doa) ? doa : null
604430
604518
  });
604431
604519
  break;
@@ -604594,6 +604682,7 @@ var init_listen = __esm({
604594
604682
  micNoiseFloorDb = null;
604595
604683
  micSpeechActive = false;
604596
604684
  lastLevelEmit = 0;
604685
+ micWaterfall = [];
604597
604686
  /**
604598
604687
  * Spawn the mic capture process and wire PCM piping + level metering.
604599
604688
  * Shared by start() and resume() so both paths meter identically.
@@ -604633,9 +604722,20 @@ var init_listen = __esm({
604633
604722
  let sumSquares = 0;
604634
604723
  const stride = samples > 4096 ? 4 : 1;
604635
604724
  let counted = 0;
604725
+ const bucketSquares = new Array(MIC_WAVEFORM_BINS).fill(0);
604726
+ const bucketCounts = new Array(MIC_WAVEFORM_BINS).fill(0);
604727
+ const spectrumSamples = [];
604728
+ const spectrumDecimate = Math.max(1, Math.floor(samples / 256));
604636
604729
  for (let i2 = 0; i2 + 1 < chunk.length; i2 += 2 * stride) {
604637
604730
  const v = chunk.readInt16LE(i2) / 32768;
604638
604731
  sumSquares += v * v;
604732
+ const sampleIndex = Math.floor(i2 / 2);
604733
+ const bucket = Math.min(MIC_WAVEFORM_BINS - 1, Math.floor(sampleIndex / Math.max(1, samples) * MIC_WAVEFORM_BINS));
604734
+ bucketSquares[bucket] += v * v;
604735
+ bucketCounts[bucket] += 1;
604736
+ if (sampleIndex % spectrumDecimate === 0 && spectrumSamples.length < 256) {
604737
+ spectrumSamples.push(v);
604738
+ }
604639
604739
  counted++;
604640
604740
  }
604641
604741
  if (counted === 0) return;
@@ -604650,18 +604750,33 @@ var init_listen = __esm({
604650
604750
  const speech = hardwareFresh ? listenLiveState.speechActive : this.micLevelDb > Math.max(-58, floor + 6);
604651
604751
  const changed = speech !== this.micSpeechActive;
604652
604752
  this.micSpeechActive = speech;
604753
+ const peak = Math.sqrt(Math.max(...bucketSquares.map((sum, idx) => sum / Math.max(1, bucketCounts[idx] ?? 1)), 0));
604754
+ const waveform = renderMicWaveform(bucketSquares, bucketCounts, peak);
604755
+ const spectrum = renderMicSpectrum(spectrumSamples);
604756
+ if (spectrum) {
604757
+ this.micWaterfall.push(spectrum);
604758
+ if (this.micWaterfall.length > MIC_WATERFALL_ROWS) {
604759
+ this.micWaterfall = this.micWaterfall.slice(-MIC_WATERFALL_ROWS);
604760
+ }
604761
+ }
604653
604762
  const now2 = Date.now();
604654
604763
  if (changed || now2 - this.lastLevelEmit >= 300) {
604655
604764
  this.lastLevelEmit = now2;
604656
604765
  updateListenLiveState({
604657
604766
  micLevelDb: Number(this.micLevelDb.toFixed(1)),
604658
604767
  noiseFloorDb: Number(floor.toFixed(1)),
604659
- speechActive: speech
604768
+ speechActive: speech,
604769
+ waveform,
604770
+ spectrum,
604771
+ waterfall: [...this.micWaterfall]
604660
604772
  });
604661
604773
  this.emit("level", {
604662
604774
  levelDb: this.micLevelDb,
604663
604775
  noiseFloorDb: floor,
604664
- speechActive: speech
604776
+ speechActive: speech,
604777
+ waveform,
604778
+ spectrum,
604779
+ waterfall: [...this.micWaterfall]
604665
604780
  });
604666
604781
  }
604667
604782
  }
@@ -604721,12 +604836,16 @@ var init_listen = __esm({
604721
604836
  */
604722
604837
  async start() {
604723
604838
  if (this.active) return "Already listening.";
604839
+ this.micWaterfall = [];
604724
604840
  updateListenLiveState({
604725
604841
  phase: "bootstrapping",
604726
604842
  model: this.config.model,
604727
604843
  backend: "",
604728
604844
  lastStatus: "starting ASR backend...",
604729
- speechActive: false
604845
+ speechActive: false,
604846
+ waveform: "",
604847
+ spectrum: "",
604848
+ waterfall: []
604730
604849
  });
604731
604850
  const micCmd = await findMicCaptureCommand();
604732
604851
  if (!micCmd) {
@@ -604933,7 +605052,8 @@ transcribe-cli error: ${transcribeCliError}` : "";
604933
605052
  this.active = false;
604934
605053
  this.owners.clear();
604935
605054
  this.blinkState = false;
604936
- updateListenLiveState({ phase: "idle", speechActive: false, micLevelDb: null, lastStatus: "stopped" });
605055
+ this.micWaterfall = [];
605056
+ updateListenLiveState({ phase: "idle", speechActive: false, micLevelDb: null, waveform: "", spectrum: "", waterfall: [], lastStatus: "stopped" });
604937
605057
  if (this.blinkTimer) {
604938
605058
  clearInterval(this.blinkTimer);
604939
605059
  this.blinkTimer = null;
@@ -604994,7 +605114,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
604994
605114
  }
604995
605115
  this.micProcess = null;
604996
605116
  }
604997
- updateListenLiveState({ phase: "paused", speechActive: false, lastStatus: "mic paused (TTS speaking)" });
605117
+ updateListenLiveState({ phase: "paused", speechActive: false, waveform: "", spectrum: "", lastStatus: "mic paused (TTS speaking)" });
604998
605118
  this.emit("paused");
604999
605119
  this.emit("recording", false);
605000
605120
  }
@@ -607018,6 +607138,7 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
607018
607138
  };
607019
607139
  const asrMicBits = asr.micLevelDb !== null ? ` mic=${asr.micLevelDb.toFixed(1)}dB${asr.speechActive ? " ●speech" : ""}${asr.doa !== null ? ` dir=${asr.doa}°` : ""}` : "";
607020
607140
  const asrLine = asr.phase !== "idle" ? `│ ├─ whisper: ${[asr.backend, asr.model].filter(Boolean).join(" ") || "starting"} — ${asrPhaseLabel[asr.phase] ?? asr.phase}${asrMicBits}` : "";
607141
+ const asrStateLine = asr.phase !== "idle" ? `│ ├─ state: phase=${asr.phase} backend=${asr.backend || "unknown"} model=${asr.model || "unknown"} vad=${asr.speechActive ? "speech" : "quiet"} floor=${asr.noiseFloorDb !== null ? `${asr.noiseFloorDb.toFixed(1)}dB` : "n/a"}` : "";
607021
607142
  const asrFinalAge = asr.lastTranscriptAt > 0 ? Math.max(0, Math.round((now2 - asr.lastTranscriptAt) / 1e3)) : null;
607022
607143
  const asrPartialAge = asr.lastPartialTranscriptAt > 0 ? Math.max(0, Math.round((now2 - asr.lastPartialTranscriptAt) / 1e3)) : null;
607023
607144
  const showPartial = asr.lastPartialTranscript && (!asr.lastTranscriptAt || asr.lastPartialTranscriptAt >= asr.lastTranscriptAt);
@@ -607027,14 +607148,23 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
607027
607148
  const audioBits = [
607028
607149
  `├─ input: ${audioSnapshot?.input || snapshot.config.selectedAudioInput || "none"}`,
607029
607150
  asrLine,
607151
+ asrStateLine,
607030
607152
  asrStatusLine,
607031
607153
  asrHeardLine,
607154
+ asr.waveform ? `│ ├─ waveform: ${asr.waveform}` : "",
607155
+ asr.spectrum ? `│ ├─ spectrum: ${asr.spectrum} ${dashboardDim("low→high freq")}` : "",
607032
607156
  audioSnapshot?.activity ? `│ ├─ activity: ${audioSnapshot.activity.waveform} rms=${audioSnapshot.activity.rmsDb.toFixed(1)}dB active=${Math.round(audioSnapshot.activity.activeRatio * 100)}%` : "",
607033
607157
  audioError ? `│ ├─ error: ${trimOneLine(audioError, 140)}` : "",
607034
607158
  transcript ? `│ ├─ asr${audioSnapshot?.asrBackend ? ` (${audioSnapshot.asrBackend})` : ""}: ${trimOneLine(transcript, 140)}` : "",
607035
607159
  audioSnapshot?.intake ? `│ ├─ intake: ${audioSnapshot.intake.intendedForAgent ? "for-agent" : "ambient"} conf=${audioSnapshot.intake.confidence.toFixed(2)} action=${audioSnapshot.intake.action}` : ""
607036
607160
  ].filter(Boolean);
607037
- for (const item of audioBits.slice(0, 9)) pushDashboardWrapped(lines, item, width);
607161
+ for (const item of audioBits.slice(0, 11)) pushDashboardWrapped(lines, item, width);
607162
+ if (asr.waterfall.length > 0) {
607163
+ lines.push(`│${truncateAnsiCell(` ├─ speech waterfall ${dashboardDim("blue quiet → red loud")}`, width - 2)}│`);
607164
+ for (const row of asr.waterfall.slice(-8)) {
607165
+ lines.push(`│${truncateAnsiCell(` │ ${row}`, width - 2)}│`);
607166
+ }
607167
+ }
607038
607168
  if (coloredSoundSummary) {
607039
607169
  lines.push(`│${truncateAnsiCell(` └─ ${coloredSoundSummary}`, width - 2)}│`);
607040
607170
  }
@@ -668547,7 +668677,7 @@ function normalizePersonName(name10) {
668547
668677
  function personKey(name10) {
668548
668678
  return `person:${normalizePersonName(name10)}`;
668549
668679
  }
668550
- function clamp0110(value2, fallback = 0) {
668680
+ function clamp0111(value2, fallback = 0) {
668551
668681
  if (typeof value2 !== "number" || !Number.isFinite(value2)) return fallback;
668552
668682
  return Math.max(0, Math.min(1, value2));
668553
668683
  }
@@ -668564,7 +668694,7 @@ function parseStructuredIdentifyResult(result) {
668564
668694
  const matches = faces.filter((face) => face["identified"] === true && typeof face["name"] === "string" && String(face["name"]).trim()).map((face) => ({
668565
668695
  name: String(face["name"]).trim(),
668566
668696
  personId: typeof face["person_id"] === "string" ? face["person_id"] : void 0,
668567
- confidence: clamp0110(face["confidence"], 0),
668697
+ confidence: clamp0111(face["confidence"], 0),
668568
668698
  margin: typeof face["margin"] === "number" ? face["margin"] : void 0,
668569
668699
  bbox: Array.isArray(face["bbox"]) ? face["bbox"].map((n2) => Number(n2)).filter(Number.isFinite) : void 0
668570
668700
  }));
@@ -668647,7 +668777,7 @@ function activePendingVisualIdentities(store2, scope, sessionId, limit = 3) {
668647
668777
  pendingId,
668648
668778
  name: name10,
668649
668779
  relation: String(meta["relation"] || "depicts"),
668650
- confidence: clamp0110(meta["confidence"], 0.92),
668780
+ confidence: clamp0111(meta["confidence"], 0.92),
668651
668781
  note: typeof meta["note"] === "string" ? meta["note"] : void 0,
668652
668782
  episodeId: ep.id,
668653
668783
  createdAt: ep.timestamp,
@@ -668756,7 +668886,7 @@ function stageVisualIdentityAssertion(options2) {
668756
668886
  target: "next_visual_media",
668757
668887
  name: name10,
668758
668888
  relation: options2.relation || "depicts",
668759
- confidence: clamp0110(options2.confidence, 0.92),
668889
+ confidence: clamp0111(options2.confidence, 0.92),
668760
668890
  note: options2.note,
668761
668891
  createdAt: Date.now(),
668762
668892
  expiresAt
@@ -668764,7 +668894,7 @@ function stageVisualIdentityAssertion(options2) {
668764
668894
  identityAssertions: [{
668765
668895
  name: name10,
668766
668896
  relation: options2.relation || "named_as",
668767
- confidence: clamp0110(options2.confidence, 0.92),
668897
+ confidence: clamp0111(options2.confidence, 0.92),
668768
668898
  assertedBy: options2.sender,
668769
668899
  note: options2.note || "Explicit user-provided identity staged for the next visual media."
668770
668900
  }],
@@ -668795,7 +668925,7 @@ function stageVisualIdentityAssertion(options2) {
668795
668925
  target: "next_visual_media",
668796
668926
  name: name10,
668797
668927
  relation: options2.relation || "depicts",
668798
- confidence: clamp0110(options2.confidence, 0.92),
668928
+ confidence: clamp0111(options2.confidence, 0.92),
668799
668929
  note: options2.note,
668800
668930
  createdAt: Date.now(),
668801
668931
  expiresAt
@@ -668804,7 +668934,7 @@ function stageVisualIdentityAssertion(options2) {
668804
668934
  identityAssertions: [{
668805
668935
  name: name10,
668806
668936
  relation: options2.relation || "named_as",
668807
- confidence: clamp0110(options2.confidence, 0.92),
668937
+ confidence: clamp0111(options2.confidence, 0.92),
668808
668938
  assertedBy: options2.sender,
668809
668939
  note: options2.note || "Explicit user-provided identity staged for the next visual media."
668810
668940
  }]
@@ -677600,7 +677730,7 @@ ${result.output}`,
677600
677730
  });
677601
677731
 
677602
677732
  // packages/cli/src/tui/stimulation.ts
677603
- function clamp0111(value2) {
677733
+ function clamp0112(value2) {
677604
677734
  return Math.max(0, Math.min(1, value2));
677605
677735
  }
677606
677736
  function cloneState(state) {
@@ -677656,7 +677786,7 @@ var init_stimulation = __esm({
677656
677786
  ...DEFAULT_STATE,
677657
677787
  ...state,
677658
677788
  phase: normalizePhase(state.phase) ?? DEFAULT_STATE.phase,
677659
- attention: clamp0111(Number.isFinite(state.attention) ? Number(state.attention) : DEFAULT_STATE.attention),
677789
+ attention: clamp0112(Number.isFinite(state.attention) ? Number(state.attention) : DEFAULT_STATE.attention),
677660
677790
  updatedAtMs: Number.isFinite(state.updatedAtMs) ? Number(state.updatedAtMs) : now2,
677661
677791
  lastStimulusAtMs: Number.isFinite(state.lastStimulusAtMs) ? Number(state.lastStimulusAtMs) : now2,
677662
677792
  messagesSinceAnalysis: Math.max(0, Math.floor(Number(state.messagesSinceAnalysis ?? 0))),
@@ -677697,11 +677827,11 @@ var init_stimulation = __esm({
677697
677827
  applyAgentDecision(channelId, decision2, nowMs = Date.now()) {
677698
677828
  const state = this.stateFor(channelId, nowMs);
677699
677829
  if (Number.isFinite(decision2.attentionScore)) {
677700
- state.attention = clamp0111(Number(decision2.attentionScore));
677830
+ state.attention = clamp0112(Number(decision2.attentionScore));
677701
677831
  } else if (Number.isFinite(decision2.attentionDelta)) {
677702
- state.attention = clamp0111(state.attention + Number(decision2.attentionDelta));
677832
+ state.attention = clamp0112(state.attention + Number(decision2.attentionDelta));
677703
677833
  } else {
677704
- state.attention = clamp0111(state.attention + (decision2.shouldReply ? 0.22 : -0.1));
677834
+ state.attention = clamp0112(state.attention + (decision2.shouldReply ? 0.22 : -0.1));
677705
677835
  }
677706
677836
  if (decision2.phase) {
677707
677837
  state.attention = Math.max(state.attention, PHASE_FLOORS[decision2.phase]);
@@ -677757,7 +677887,7 @@ var init_stimulation = __esm({
677757
677887
  });
677758
677888
 
677759
677889
  // packages/cli/src/tui/pid-controller.ts
677760
- function clamp0112(x) {
677890
+ function clamp0113(x) {
677761
677891
  if (!Number.isFinite(x)) return 0;
677762
677892
  if (x < 0) return 0;
677763
677893
  if (x > 1) return 1;
@@ -677821,7 +677951,7 @@ var init_pid_controller = __esm({
677821
677951
  const dt = st.lastSampleAt > 0 ? now2 - st.lastSampleAt : 1e3;
677822
677952
  const derivative = dt > 0 ? (error - st.lastError) / dt : 0;
677823
677953
  const u = st.config.kp * error + st.config.ki * st.integral + st.config.kd * derivative;
677824
- st.output = clamp0112(st.output + u);
677954
+ st.output = clamp0113(st.output + u);
677825
677955
  st.lastError = error;
677826
677956
  st.lastSampleAt = now2;
677827
677957
  st.samples += 1;
@@ -678350,7 +678480,7 @@ function buildReplyOpportunities(input, openQuestions) {
678350
678480
  function daydreamOpportunityId(input, trigger) {
678351
678481
  return createHash39("sha1").update(`${input.sessionKey}:${input.generatedAtMs}:${trigger}`).digest("hex").slice(0, 16);
678352
678482
  }
678353
- function clamp0113(value2) {
678483
+ function clamp0114(value2) {
678354
678484
  if (!Number.isFinite(value2)) return 0;
678355
678485
  return Math.max(0, Math.min(1, value2));
678356
678486
  }
@@ -678367,7 +678497,7 @@ function pushStimulationSignal(signals, signal, source, weight) {
678367
678497
  signals.push({
678368
678498
  signal: cleanSignal,
678369
678499
  source: cleanSource,
678370
- weight: clamp0113(weight)
678500
+ weight: clamp0114(weight)
678371
678501
  });
678372
678502
  }
678373
678503
  function buildMetaAnalysisSignals(input) {
@@ -678497,7 +678627,7 @@ function buildCuriosityThreads(input, openQuestions, stimulationSignals) {
678497
678627
  question: text2.endsWith("?") || text2.endsWith("?") ? text2 : `What should be learned or clarified from: ${text2 || entry.mediaSummary || "recent media"}?`,
678498
678628
  rationale: "Human curiosity, uncertainty, or multimodal content makes this a useful idle exploration target.",
678499
678629
  sourceMessages: messageId,
678500
- intensity: clamp0113(0.5 + replyBoost + mediaBoost + questionBoost)
678630
+ intensity: clamp0114(0.5 + replyBoost + mediaBoost + questionBoost)
678501
678631
  });
678502
678632
  }
678503
678633
  for (const question of openQuestions.slice(-4)) {
@@ -678520,7 +678650,7 @@ function buildCuriosityThreads(input, openQuestions, stimulationSignals) {
678520
678650
  question: `Is there a useful clarification or memory consolidation around ${strongest.source}?`,
678521
678651
  rationale: "Strongest stimulation signal can seed a low-intrusion reflection target.",
678522
678652
  sourceMessages: [],
678523
- intensity: clamp0113(strongest.weight * 0.72)
678653
+ intensity: clamp0114(strongest.weight * 0.72)
678524
678654
  });
678525
678655
  }
678526
678656
  return threads.sort((a2, b) => b.intensity - a2.intensity).slice(0, 8);
@@ -678600,7 +678730,7 @@ function buildOutreachPlans(input, curiosityThreads) {
678600
678730
  purpose: "Continue the public thread only when the live model judges that the group would benefit from a concise follow-up.",
678601
678731
  draftIntent: "Ask one concrete clarification, offer one useful synthesis, or stay silent if the room has moved on.",
678602
678732
  gate: "model_decision",
678603
- confidence: clamp0113(thread.intensity * 0.86)
678733
+ confidence: clamp0114(thread.intensity * 0.86)
678604
678734
  });
678605
678735
  const participant = participantForThread(input, thread);
678606
678736
  if (!participant) continue;
@@ -678612,7 +678742,7 @@ function buildOutreachPlans(input, curiosityThreads) {
678612
678742
  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.",
678613
678743
  draftIntent: "Reference the public thread briefly, ask permission to continue privately, and do not reveal hidden meta-analysis.",
678614
678744
  gate: "admin_review",
678615
- confidence: clamp0113(thread.intensity * 0.58)
678745
+ confidence: clamp0114(thread.intensity * 0.58)
678616
678746
  });
678617
678747
  }
678618
678748
  return plans.slice(0, 8);
@@ -679944,7 +680074,7 @@ function numberOr(value2, fallback) {
679944
680074
  function isNumber(value2) {
679945
680075
  return typeof value2 === "number" && Number.isFinite(value2);
679946
680076
  }
679947
- function clamp0114(value2) {
680077
+ function clamp0115(value2) {
679948
680078
  return Math.max(0, Math.min(1, Number.isFinite(value2) ? value2 : 0));
679949
680079
  }
679950
680080
  function iso(ts) {
@@ -680128,8 +680258,8 @@ function normalizeRelationship(raw) {
680128
680258
  kind: value2.kind,
680129
680259
  fromKey: String(value2.fromKey),
680130
680260
  toKey: String(value2.toKey),
680131
- confidence: clamp0114(numberOr(value2.confidence, 0)),
680132
- weight: clamp0114(numberOr(value2.weight, 0)),
680261
+ confidence: clamp0115(numberOr(value2.confidence, 0)),
680262
+ weight: clamp0115(numberOr(value2.weight, 0)),
680133
680263
  firstSeenAt: numberOr(value2.firstSeenAt, Date.now()),
680134
680264
  lastSeenAt: numberOr(value2.lastSeenAt, Date.now()),
680135
680265
  evidenceMessageIds: Array.isArray(value2.evidenceMessageIds) ? value2.evidenceMessageIds.filter(isNumber).slice(-40) : [],
@@ -680148,7 +680278,7 @@ function normalizePreferences(raw) {
680148
680278
  if (!evidence || typeof evidence !== "object") continue;
680149
680279
  out[actorKey][key] = {
680150
680280
  value: Math.max(-1, Math.min(1, numberOr(evidence.value, 0))),
680151
- confidence: clamp0114(numberOr(evidence.confidence, 0)),
680281
+ confidence: clamp0115(numberOr(evidence.confidence, 0)),
680152
680282
  updatedAt: numberOr(evidence.updatedAt, Date.now()),
680153
680283
  evidenceMessageIds: Array.isArray(evidence.evidenceMessageIds) ? evidence.evidenceMessageIds.filter(isNumber).slice(-12) : [],
680154
680284
  note: compactOptional(evidence.note, 220)
@@ -680162,7 +680292,7 @@ function normalizePreferences(raw) {
680162
680292
  out[actorKey].replyMode = {
680163
680293
  mode,
680164
680294
  scope: normalizeReplyPreferenceScope(record["scope"]),
680165
- confidence: clamp0114(numberOr(record["confidence"], 0.8)),
680295
+ confidence: clamp0115(numberOr(record["confidence"], 0.8)),
680166
680296
  updatedAt: numberOr(record["updatedAt"], Date.now()),
680167
680297
  evidenceMessageIds: Array.isArray(record["evidenceMessageIds"]) ? record["evidenceMessageIds"].filter(isNumber).slice(-12) : [],
680168
680298
  note: compactOptional(record["note"], 220),
@@ -680252,7 +680382,7 @@ function normalizeOutcome2(raw) {
680252
680382
  replyToMessageId: typeof value2.replyToMessageId === "number" ? value2.replyToMessageId : void 0,
680253
680383
  route: value2.route === "action" ? "action" : "chat",
680254
680384
  shouldReply: value2.shouldReply === true,
680255
- confidence: clamp0114(numberOr(value2.confidence, 0)),
680385
+ confidence: clamp0115(numberOr(value2.confidence, 0)),
680256
680386
  reason: compact3(value2.reason || "", 280),
680257
680387
  source: compact3(value2.source || "unknown", 80),
680258
680388
  silentDisposition: compactOptional(value2.silentDisposition, 280),
@@ -680264,7 +680394,7 @@ function normalizeOutcome2(raw) {
680264
680394
  scenarioNote: compactOptional(value2.scenarioNote, 360),
680265
680395
  scenarioId: compactOptional(value2.scenarioId, 160),
680266
680396
  scenarioLabel: compactOptional(value2.scenarioLabel, 160),
680267
- scenarioConfidence: typeof value2.scenarioConfidence === "number" && Number.isFinite(value2.scenarioConfidence) ? clamp0114(value2.scenarioConfidence) : void 0,
680397
+ scenarioConfidence: typeof value2.scenarioConfidence === "number" && Number.isFinite(value2.scenarioConfidence) ? clamp0115(value2.scenarioConfidence) : void 0,
680268
680398
  scenarioObjective: compactOptional(value2.scenarioObjective, 360),
680269
680399
  scenarioStateLoop: compactOptional(value2.scenarioStateLoop, 360),
680270
680400
  salienceSignals: Array.isArray(value2.salienceSignals) ? value2.salienceSignals.map(String).slice(0, 16) : [],
@@ -680282,7 +680412,7 @@ function normalizeDaydreamOpportunity(raw) {
680282
680412
  artifactId: String(value2.artifactId || "unknown"),
680283
680413
  generatedAt: String(value2.generatedAt || (/* @__PURE__ */ new Date()).toISOString()),
680284
680414
  trigger: compact3(value2.trigger || "", 240),
680285
- confidence: clamp0114(numberOr(value2.confidence, 0)),
680415
+ confidence: clamp0115(numberOr(value2.confidence, 0)),
680286
680416
  lifecycle,
680287
680417
  firstSeenAt: numberOr(value2.firstSeenAt, Date.now()),
680288
680418
  updatedAt: numberOr(value2.updatedAt, Date.now()),
@@ -680339,7 +680469,7 @@ function commitTelegramSocialDecision(state, input) {
680339
680469
  replyToMessageId: input.replyToMessageId,
680340
680470
  route: input.route,
680341
680471
  shouldReply: input.shouldReply,
680342
- confidence: clamp0114(input.confidence),
680472
+ confidence: clamp0115(input.confidence),
680343
680473
  reason: compact3(input.reason, 280),
680344
680474
  source: compact3(input.source, 80),
680345
680475
  silentDisposition: compactOptional(input.silentDisposition, 280),
@@ -680351,7 +680481,7 @@ function commitTelegramSocialDecision(state, input) {
680351
680481
  scenarioNote: compactOptional(input.scenarioNote, 360),
680352
680482
  scenarioId: compactOptional(input.scenarioId, 160),
680353
680483
  scenarioLabel: compactOptional(input.scenarioLabel, 160),
680354
- scenarioConfidence: input.scenarioConfidence === void 0 ? void 0 : clamp0114(input.scenarioConfidence),
680484
+ scenarioConfidence: input.scenarioConfidence === void 0 ? void 0 : clamp0115(input.scenarioConfidence),
680355
680485
  scenarioObjective: compactOptional(input.scenarioObjective, 360),
680356
680486
  scenarioStateLoop: compactOptional(input.scenarioStateLoop, 360),
680357
680487
  salienceSignals: [...new Set((input.salienceSignals ?? []).map(String))].slice(0, 16),
@@ -680375,7 +680505,7 @@ function registerDaydreamOpportunities(state, opportunities, now2 = Date.now())
680375
680505
  artifactId: opportunity.artifactId || "unknown",
680376
680506
  generatedAt: opportunity.generatedAt || new Date(now2).toISOString(),
680377
680507
  trigger: compact3(opportunity.trigger, 240),
680378
- confidence: clamp0114(opportunity.confidence),
680508
+ confidence: clamp0115(opportunity.confidence),
680379
680509
  lifecycle: "proposed",
680380
680510
  firstSeenAt: now2,
680381
680511
  updatedAt: now2,
@@ -680385,7 +680515,7 @@ function registerDaydreamOpportunities(state, opportunities, now2 = Date.now())
680385
680515
  };
680386
680516
  if (existing) {
680387
680517
  item.trigger = compact3(opportunity.trigger, 240) || item.trigger;
680388
- item.confidence = clamp0114(opportunity.confidence);
680518
+ item.confidence = clamp0115(opportunity.confidence);
680389
680519
  item.updatedAt = now2;
680390
680520
  }
680391
680521
  state.daydreamOpportunities[id2] = item;
@@ -680412,7 +680542,7 @@ function setTelegramReplyModePreference(state, input) {
680412
680542
  const next = {
680413
680543
  mode: input.mode,
680414
680544
  scope: input.scope,
680415
- confidence: Math.max(existing?.confidence ?? 0, clamp0114(input.confidence ?? 0.84)),
680545
+ confidence: Math.max(existing?.confidence ?? 0, clamp0115(input.confidence ?? 0.84)),
680416
680546
  updatedAt: now2,
680417
680547
  evidenceMessageIds: appendUnique(existing?.evidenceMessageIds ?? [], input.messageId, 12),
680418
680548
  note: compactOptional(input.note, 220),
@@ -680592,8 +680722,8 @@ function upsertRelationship(state, kind, fromKey, toKey, messageId, confidence2,
680592
680722
  evidenceMessageIds: [],
680593
680723
  source
680594
680724
  };
680595
- edge.confidence = Math.max(edge.confidence, clamp0114(confidence2));
680596
- edge.weight = Math.min(1, edge.weight + 0.12 + clamp0114(confidence2) * 0.2);
680725
+ edge.confidence = Math.max(edge.confidence, clamp0115(confidence2));
680726
+ edge.weight = Math.min(1, edge.weight + 0.12 + clamp0115(confidence2) * 0.2);
680597
680727
  edge.lastSeenAt = now2;
680598
680728
  edge.evidenceMessageIds = appendUnique(edge.evidenceMessageIds, messageId, 40);
680599
680729
  edge.note = compactOptional(note, 260) || edge.note;
@@ -680635,7 +680765,7 @@ function setPreference(vector, key, value2, confidence2, messageId, now2, note)
680635
680765
  const existing = vector[key];
680636
680766
  vector[key] = {
680637
680767
  value: existing ? existing.value * 0.7 + value2 * 0.3 : value2,
680638
- confidence: Math.max(existing?.confidence ?? 0, clamp0114(confidence2)),
680768
+ confidence: Math.max(existing?.confidence ?? 0, clamp0115(confidence2)),
680639
680769
  updatedAt: now2,
680640
680770
  evidenceMessageIds: appendUnique(existing?.evidenceMessageIds ?? [], messageId, 12),
680641
680771
  note
@@ -680817,7 +680947,7 @@ async function queryVisionModel(modelName, imagePath, prompt = "Describe what yo
680817
680947
  return "";
680818
680948
  }
680819
680949
  }
680820
- function clamp0115(value2, fallback = 0) {
680950
+ function clamp0116(value2, fallback = 0) {
680821
680951
  if (typeof value2 !== "number" || !Number.isFinite(value2)) return fallback;
680822
680952
  return Math.max(0, Math.min(1, value2));
680823
680953
  }
@@ -680834,9 +680964,9 @@ function parseVisualMemoryRecognize(raw) {
680834
680964
  label: String(match.label).trim(),
680835
680965
  objectId: typeof match.object_id === "string" ? match.object_id : void 0,
680836
680966
  matchedAlias: typeof match.matched_alias === "string" ? match.matched_alias : void 0,
680837
- blendedScore: clamp0115(match.blended_score, 0),
680838
- imageSimilarity: typeof match.image_similarity === "number" ? clamp0115(match.image_similarity, 0) : void 0,
680839
- textSimilarity: typeof match.text_similarity === "number" ? clamp0115(match.text_similarity, 0) : void 0
680967
+ blendedScore: clamp0116(match.blended_score, 0),
680968
+ imageSimilarity: typeof match.image_similarity === "number" ? clamp0116(match.image_similarity, 0) : void 0,
680969
+ textSimilarity: typeof match.text_similarity === "number" ? clamp0116(match.text_similarity, 0) : void 0
680840
680970
  })).sort((a2, b) => b.blendedScore - a2.blendedScore).slice(0, 5);
680841
680971
  }
680842
680972
  function formatVisualFamiliarityContext(result) {
@@ -699787,7 +699917,7 @@ __export(voicechat_exports, {
699787
699917
  isLikelyAgentSpeechEcho: () => isLikelyAgentSpeechEcho
699788
699918
  });
699789
699919
  import { EventEmitter as EventEmitter12 } from "node:events";
699790
- function clamp0116(x) {
699920
+ function clamp0117(x) {
699791
699921
  return x < 0 ? 0 : x > 1 ? 1 : x;
699792
699922
  }
699793
699923
  function alnumRatio(s2) {
@@ -699840,9 +699970,9 @@ function computeSignalFromText(text2, confidence2) {
699840
699970
  score -= repeatingCharPenalty(t2) * 0.4;
699841
699971
  score -= gibberishTokenPenalty(t2) * 0.8;
699842
699972
  if (typeof confidence2 === "number" && !Number.isNaN(confidence2)) {
699843
- score = 0.7 * score + 0.3 * clamp0116(confidence2);
699973
+ score = 0.7 * score + 0.3 * clamp0117(confidence2);
699844
699974
  }
699845
- return clamp0116(score);
699975
+ return clamp0117(score);
699846
699976
  }
699847
699977
  function truncateForLog(s2, n2) {
699848
699978
  return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "…";
@@ -700227,7 +700357,9 @@ Rules:
700227
700357
  };
700228
700358
  this._onError = (err) => {
700229
700359
  const msg = err instanceof Error ? err.message : String(err);
700230
- this.onStatus(`ASR error (voicechat continues without mic): ${msg.slice(0, 80)}`);
700360
+ if (this.verbose) {
700361
+ this.onStatus(`ASR error (voicechat continues without mic): ${msg.slice(0, 80)}`);
700362
+ }
700231
700363
  if (this.active && !this._retryMicTimer) {
700232
700364
  this._retryMicTimer = setTimeout(async () => {
700233
700365
  this._retryMicTimer = null;
@@ -700334,7 +700466,7 @@ Rules:
700334
700466
  }
700335
700467
  }, MAX_SEGMENT_MS);
700336
700468
  }
700337
- const signalScore = typeof snr === "number" && !Number.isNaN(snr) ? clamp0116(snr) : computeSignalFromText(text2, confidence2);
700469
+ const signalScore = typeof snr === "number" && !Number.isNaN(snr) ? clamp0117(snr) : computeSignalFromText(text2, confidence2);
700338
700470
  this.lastSignalScore = signalScore;
700339
700471
  if (consensus !== void 0) {
700340
700472
  this.consensusMetadataSeen = true;
@@ -739413,7 +739545,16 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
739413
739545
  if (!available) {
739414
739546
  return "ASR runtime unavailable. Omnius attempted managed transcribe-cli and Whisper fallback setup; check ~/.omnius/runtimes/asr and ~/.omnius/venv.";
739415
739547
  }
739548
+ let lastRenderedTranscript = "";
739549
+ let lastRenderedTranscriptAt = 0;
739416
739550
  engine.on("transcript", (text2, isFinal) => {
739551
+ const normalizedTranscript = text2.trim();
739552
+ const now2 = Date.now();
739553
+ if (normalizedTranscript && normalizedTranscript === lastRenderedTranscript && now2 - lastRenderedTranscriptAt < 2500) {
739554
+ return;
739555
+ }
739556
+ lastRenderedTranscript = normalizedTranscript;
739557
+ lastRenderedTranscriptAt = now2;
739417
739558
  if (engine.currentMode === "confirm") {
739418
739559
  writeContent(
739419
739560
  () => renderInfo(`Heard: "${text2}" ${c3.dim("(press Enter to submit)")}`)
@@ -739837,11 +739978,6 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
739837
739978
  listenEng.on("level", (evt) => {
739838
739979
  statusBar.setMicActivity(evt.speechActive, evt.levelDb);
739839
739980
  });
739840
- listenEng.on("info", (msg) => {
739841
- if (/consensus rejected|loading whisper|whisper model loaded|Whisper VAD|no accepted speech text|very short utterance/i.test(msg)) {
739842
- writeContent(() => renderInfo(`[voicechat/asr] ${msg}`));
739843
- }
739844
- });
739845
739981
  }
739846
739982
  const summaryRunner = {
739847
739983
  injectUserMessage(content) {
@@ -454,7 +454,7 @@ def main():
454
454
  help="Second whisper model run in parallel on finalized utterances; transcripts are only emitted when both models agree. 'off' disables.")
455
455
  parser.add_argument("--consensus-threshold", type=float, default=0.55,
456
456
  help="Token similarity (0-1) required between the two models' transcripts.")
457
- parser.add_argument("--silence-ms", type=float, default=900,
457
+ parser.add_argument("--silence-ms", type=float, default=3000,
458
458
  help="Sustained silence that finalizes an utterance.")
459
459
  parser.add_argument("--preroll-ms", type=float, default=600,
460
460
  help="Audio kept from before speech onset.")
@@ -577,7 +577,6 @@ def main():
577
577
  def transcribe_final(samples):
578
578
  nonlocal last_final_text
579
579
  if len(samples) < int(0.4 * SAMPLE_RATE):
580
- emit_status("Whisper ignored very short utterance.")
581
580
  return
582
581
  samples = amplify(samples)
583
582
  try:
@@ -585,7 +584,6 @@ def main():
585
584
 
586
585
  text = _segment_filtered_text(result)
587
586
  if not text:
588
- emit_status("Whisper final produced no accepted speech text.")
589
587
  return
590
588
  if text == last_final_text:
591
589
  return
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.439",
3
+ "version": "1.0.441",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.439",
9
+ "version": "1.0.441",
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.439",
3
+ "version": "1.0.441",
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",