omnius 1.0.636 → 1.0.638

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
@@ -5824,6 +5824,17 @@ function managedEnv3(extra = {}) {
5824
5824
  function sha256File4(path16) {
5825
5825
  return createHash6("sha256").update(readFileSync10(path16)).digest("hex");
5826
5826
  }
5827
+ function speakerSupportManifest() {
5828
+ return SPEAKER_SUPPORT_WHEELS.map((wheel) => ({
5829
+ distribution: wheel.distribution,
5830
+ version: wheel.version,
5831
+ digest: `sha256:${wheel.digest}`
5832
+ }));
5833
+ }
5834
+ function hasExpectedSpeakerSupportPackages(packages) {
5835
+ const expected = speakerSupportManifest();
5836
+ return Array.isArray(packages) && packages.length === expected.length && expected.every((item) => packages.some((candidate) => candidate.distribution === item.distribution && candidate.version === item.version && candidate.digest === item.digest));
5837
+ }
5827
5838
  function usesSystemSitePackages() {
5828
5839
  try {
5829
5840
  return /^include-system-site-packages\s*=\s*true\s*$/im.test(readFileSync10(join11(venvDir2(), "pyvenv.cfg"), "utf8"));
@@ -5834,7 +5845,7 @@ function usesSystemSitePackages() {
5834
5845
  function loadManifest3() {
5835
5846
  try {
5836
5847
  const manifest = JSON.parse(readFileSync10(manifestPath3(), "utf8"));
5837
- if (manifest.runtimeVersion !== RUNTIME_VERSION3 || manifest.model !== MODEL_NAME2 || manifest.modelRevision !== MODEL_REVISION2 || manifest.modelDigest !== `sha256:${MODEL_SHA2562}` || manifest.backend !== "onnxruntime-cpu" || manifest.onnxRuntimeVersion !== ONNXRUNTIME_VERSION || manifest.torchaudioVersion !== TORCHAUDIO_VERSION || !manifest.torchaudioWheel || !manifest.torchVersion || !manifest.torchSitePackages || !existsSync11(modelPath2()) || !existsSync11(managedPython())) {
5848
+ if (manifest.runtimeVersion !== RUNTIME_VERSION3 || manifest.model !== MODEL_NAME2 || manifest.modelRevision !== MODEL_REVISION2 || manifest.modelDigest !== `sha256:${MODEL_SHA2562}` || manifest.backend !== "onnxruntime-cpu" || manifest.onnxRuntimeVersion !== ONNXRUNTIME_VERSION || manifest.torchaudioVersion !== TORCHAUDIO_VERSION || !hasExpectedSpeakerSupportPackages(manifest.supportPackages) || !manifest.torchaudioWheel || !manifest.torchVersion || !manifest.torchSitePackages || !existsSync11(modelPath2()) || !existsSync11(managedPython())) {
5838
5849
  return null;
5839
5850
  }
5840
5851
  return sha256File4(modelPath2()) === MODEL_SHA2562 ? manifest : null;
@@ -5864,6 +5875,25 @@ function requiredJetson2() {
5864
5875
  function bootstrapPython() {
5865
5876
  return process.env["OMNIUS_AUDIO_PYTHON"]?.trim() || "python3";
5866
5877
  }
5878
+ function processDiagnostic(error) {
5879
+ if (error instanceof AsyncProcessError) {
5880
+ const detail = `${error.stderr.toString("utf8")}
5881
+ ${error.stdout.toString("utf8")}`.trim();
5882
+ if (detail)
5883
+ return detail.slice(-4e3);
5884
+ }
5885
+ return (error instanceof Error ? error.message : String(error)).slice(-4e3);
5886
+ }
5887
+ function describeSpeakerRuntimeProbeError(detail) {
5888
+ const match = detail.match(/ModuleNotFoundError:\s*No module named ['"]([^'"]+)['"]/i);
5889
+ if (match?.[1]) {
5890
+ return `Managed speaker runtime is missing Python module '${match[1]}'. It is intentionally isolated from project/user site packages.`;
5891
+ }
5892
+ return detail.slice(-4e3);
5893
+ }
5894
+ function runtimeProbeError(error) {
5895
+ return describeSpeakerRuntimeProbeError(processDiagnostic(error));
5896
+ }
5867
5897
  async function probeRuntime(python2) {
5868
5898
  if (!python2 || python2.includes("/") && !existsSync11(python2)) {
5869
5899
  return { available: false, providers: [] };
@@ -5903,8 +5933,8 @@ async function probeRuntime(python2) {
5903
5933
  torchaudioVersion: parsed.torchaudio,
5904
5934
  providers
5905
5935
  };
5906
- } catch {
5907
- return { available: false, providers: [] };
5936
+ } catch (error) {
5937
+ return { available: false, providers: [], error: runtimeProbeError(error) };
5908
5938
  }
5909
5939
  }
5910
5940
  function isExpectedJetPackTorchVersion(version5) {
@@ -5915,26 +5945,24 @@ async function inspectBootstrapPython(python2) {
5915
5945
  throw new Error("OMNIUS_AUDIO_PYTHON does not name a usable JetPack Python interpreter");
5916
5946
  }
5917
5947
  const script = [
5918
- "import json,os,sys,sysconfig,torch",
5948
+ "import json,os,sys,sysconfig",
5919
5949
  "assert sys.version_info[:2] == (3, 10), 'CPython 3.10 is required by the pinned ONNX Runtime wheel'",
5920
5950
  "site = sysconfig.get_paths()['purelib']",
5921
5951
  "assert os.path.isdir(site), 'JetPack Python has no usable site-packages directory'",
5922
- "print(json.dumps({'python':sys.version.split()[0], 'torch':torch.__version__, 'torch_cuda':torch.version.cuda, 'site':site}))"
5952
+ "print(json.dumps({'python':sys.version.split()[0], 'site':site}))"
5923
5953
  ].join("\n");
5924
5954
  try {
5925
5955
  const output2 = await execFileText2(python2, ["-c", script], { timeout: 3e4, env: managedEnv3() });
5926
5956
  const parsed = JSON.parse(output2.trim().split(/\r?\n/).pop() || "{}");
5927
- if (!parsed.python || !parsed.torch || !isExpectedJetPackTorchVersion(parsed.torch) || !String(parsed.torch_cuda ?? "").startsWith(JETPACK_CUDA_VERSION) || !parsed.site || !isAbsolute3(parsed.site) || !existsSync11(parsed.site)) {
5928
- throw new Error(`Expected JetPack Torch ${JETPACK_TORCH_ABI}.x built for CUDA ${JETPACK_CUDA_VERSION}; found torch=${parsed.torch ?? "missing"}, cuda=${parsed.torch_cuda ?? "missing"}`);
5957
+ if (!parsed.python || !parsed.site || !isAbsolute3(parsed.site) || !existsSync11(parsed.site)) {
5958
+ throw new Error("OMNIUS_AUDIO_PYTHON did not expose a usable CPython 3.10 site-packages directory");
5929
5959
  }
5930
5960
  return {
5931
5961
  pythonVersion: parsed.python,
5932
- torchVersion: parsed.torch,
5933
- torchCudaVersion: parsed.torch_cuda ?? null,
5934
5962
  torchSitePackages: resolvePath(parsed.site)
5935
5963
  };
5936
5964
  } catch (error) {
5937
- throw new Error(`JetPack Torch ${JETPACK_TORCH_ABI}.x/CUDA ${JETPACK_CUDA_VERSION} is required in OMNIUS_AUDIO_PYTHON. Omnius will not install or replace Torch: ` + (error instanceof Error ? error.message : String(error)));
5965
+ throw new Error(`OMNIUS_AUDIO_PYTHON bootstrap inspection failed: ${processDiagnostic(error)}`);
5938
5966
  }
5939
5967
  }
5940
5968
  async function managedSitePackages(python2) {
@@ -5999,6 +6027,38 @@ async function materializeTorchaudioWheel(wheel) {
5999
6027
  }
6000
6028
  return source;
6001
6029
  }
6030
+ async function installPinnedSpeakerSupportDependencies(python2) {
6031
+ for (const wheel of SPEAKER_SUPPORT_WHEELS) {
6032
+ const filename = basename(new URL(wheel.source).pathname);
6033
+ if (!filename.endsWith(".whl")) {
6034
+ throw new Error(`Pinned speaker support wheel for ${wheel.distribution} has an invalid filename`);
6035
+ }
6036
+ const localWheel = join11(speakerEmbeddingRuntimeDir(), "artifacts", wheel.digest, filename);
6037
+ try {
6038
+ await downloadChecked2(wheel.source, localWheel, wheel.digest);
6039
+ await execFileText2(python2, [
6040
+ "-m",
6041
+ "pip",
6042
+ "install",
6043
+ "--disable-pip-version-check",
6044
+ "--no-deps",
6045
+ "--no-index",
6046
+ "--force-reinstall",
6047
+ localWheel
6048
+ ], { timeout: SETUP_TIMEOUT_MS3, env: managedEnv3() });
6049
+ await execFileText2(python2, [
6050
+ "-c",
6051
+ [
6052
+ "import importlib.metadata",
6053
+ `import ${wheel.importName}`,
6054
+ `assert importlib.metadata.version('${wheel.distribution}') == '${wheel.version}'`
6055
+ ].join("\n")
6056
+ ], { timeout: 3e4, env: managedEnv3() });
6057
+ } catch (error) {
6058
+ throw new Error(`Managed speaker venv could not install required support module '${wheel.importName}' (${wheel.distribution}==${wheel.version}): ${processDiagnostic(error)}`);
6059
+ }
6060
+ }
6061
+ }
6002
6062
  async function installPinnedTorchaudio(python2, wheel) {
6003
6063
  const localWheel = await materializeTorchaudioWheel(wheel);
6004
6064
  await execFileText2(python2, [
@@ -6088,6 +6148,7 @@ async function getSpeakerEmbeddingReadiness() {
6088
6148
  torch_version: runtime2.torchVersion,
6089
6149
  torch_cuda_version: runtime2.torchCudaVersion,
6090
6150
  torchaudio_version: runtime2.torchaudioVersion,
6151
+ support_packages: manifest?.supportPackages,
6091
6152
  ...manifest ? {
6092
6153
  torchaudio_wheel: {
6093
6154
  source: manifest.torchaudioWheel.source,
@@ -6097,7 +6158,8 @@ async function getSpeakerEmbeddingReadiness() {
6097
6158
  torch_site_packages: manifest.torchSitePackages
6098
6159
  } : {},
6099
6160
  providers: runtime2.providers,
6100
- imports_verified: importsVerified
6161
+ imports_verified: importsVerified,
6162
+ ...runtime2.error ? { probe_error: runtime2.error } : {}
6101
6163
  },
6102
6164
  worker: {
6103
6165
  ready: Boolean(state3.ready && state3.worker?.exitCode === null && state3.worker.signalCode === null),
@@ -6120,12 +6182,13 @@ async function ensureSpeakerEmbeddingSetup() {
6120
6182
  const bootstrapRuntime = await inspectBootstrapPython(bootstrap2);
6121
6183
  await createManagedVenv(bootstrap2, bootstrapRuntime.torchSitePackages);
6122
6184
  const python2 = managedPython();
6185
+ await installPinnedSpeakerSupportDependencies(python2);
6123
6186
  const torchaudioWheel = configuredTorchaudioWheel();
6124
6187
  await installPinnedTorchaudio(python2, torchaudioWheel);
6125
6188
  await installPinnedOnnxRuntime(python2);
6126
6189
  const runtime2 = await probeRuntime(python2);
6127
6190
  if (!runtime2.available || runtime2.torchaudioVersion !== TORCHAUDIO_VERSION || !runtime2.torchVersion || !isExpectedJetPackTorchVersion(runtime2.torchVersion) || !String(runtime2.torchCudaVersion ?? "").startsWith(JETPACK_CUDA_VERSION) || !runtime2.torchPath || !resolvePath(runtime2.torchPath).startsWith(bootstrapRuntime.torchSitePackages) || !runtime2.providers.includes("CPUExecutionProvider")) {
6128
- throw new Error("Managed Torchaudio/Torch ABI validation failed after speaker setup. The exact CPU kaldi.fbank probe must use the operator-selected JetPack Torch 2.2/CUDA 12.2 and managed torchaudio 2.2.0.");
6191
+ throw new Error(`Managed Torchaudio/Torch ABI validation failed after speaker setup${runtime2.error ? `: ${runtime2.error}` : ""}. The exact CPU kaldi.fbank probe must use the operator-selected JetPack Torch 2.2/CUDA 12.2 and managed torchaudio 2.2.0.`);
6129
6192
  }
6130
6193
  await downloadChecked2(MODEL_URL2, modelPath2(), MODEL_SHA2562);
6131
6194
  const manifest = {
@@ -6136,6 +6199,7 @@ async function ensureSpeakerEmbeddingSetup() {
6136
6199
  backend: "onnxruntime-cpu",
6137
6200
  onnxRuntimeVersion: ONNXRUNTIME_VERSION,
6138
6201
  torchaudioVersion: runtime2.torchaudioVersion,
6202
+ supportPackages: speakerSupportManifest(),
6139
6203
  torchaudioWheel,
6140
6204
  pythonVersion: runtime2.pythonVersion ?? bootstrapRuntime.pythonVersion,
6141
6205
  torchVersion: runtime2.torchVersion,
@@ -6376,7 +6440,7 @@ async function bootstrapSpeakerEmbeddingRuntime() {
6376
6440
  await ensureSpeakerEmbeddingSetup();
6377
6441
  return activateSpeakerEmbedding();
6378
6442
  }
6379
- var RUNTIME_VERSION3, MODEL_NAME2, MODEL_REVISION2, MODEL_FILE, MODEL_URL2, MODEL_SHA2562, ONNXRUNTIME_VERSION, ONNXRUNTIME_WHEEL, ONNXRUNTIME_WHEEL_SHA256, TORCHAUDIO_VERSION, TORCHAUDIO_WHEEL, TORCHAUDIO_WHEEL_SHA256, JETPACK_TORCH_ABI, JETPACK_CUDA_VERSION, SETUP_TIMEOUT_MS3, START_TIMEOUT_MS3, EMBED_TIMEOUT_MS2, WESPEAKER_CAMPP_ONNX_SHA256, WESPEAKER_CAMPP_MODEL_REVISION, WESPEAKER_CAMPP_ONNXRUNTIME_VERSION, WESPEAKER_CAMPP_EMBEDDING_SET_SLUG, state3;
6443
+ var RUNTIME_VERSION3, MODEL_NAME2, MODEL_REVISION2, MODEL_FILE, MODEL_URL2, MODEL_SHA2562, ONNXRUNTIME_VERSION, ONNXRUNTIME_WHEEL, ONNXRUNTIME_WHEEL_SHA256, TORCHAUDIO_VERSION, TORCHAUDIO_WHEEL, TORCHAUDIO_WHEEL_SHA256, TYPING_EXTENSIONS_VERSION, TYPING_EXTENSIONS_WHEEL, TYPING_EXTENSIONS_WHEEL_SHA256, JETPACK_TORCH_ABI, JETPACK_CUDA_VERSION, SETUP_TIMEOUT_MS3, START_TIMEOUT_MS3, EMBED_TIMEOUT_MS2, WESPEAKER_CAMPP_ONNX_SHA256, WESPEAKER_CAMPP_MODEL_REVISION, WESPEAKER_CAMPP_ONNXRUNTIME_VERSION, WESPEAKER_CAMPP_EMBEDDING_SET_SLUG, SPEAKER_SUPPORT_WHEELS, state3;
6380
6444
  var init_speaker_embedding_runtime = __esm({
6381
6445
  "packages/execution/dist/speaker-embedding-runtime.js"() {
6382
6446
  "use strict";
@@ -6384,7 +6448,7 @@ var init_speaker_embedding_runtime = __esm({
6384
6448
  init_process_async();
6385
6449
  init_model_store();
6386
6450
  init_venv_paths();
6387
- RUNTIME_VERSION3 = 2;
6451
+ RUNTIME_VERSION3 = 3;
6388
6452
  MODEL_NAME2 = "wespeaker-voxceleb-campplus";
6389
6453
  MODEL_REVISION2 = "acf623ad8ca746e50baa432255cf8fc57c669c45";
6390
6454
  MODEL_FILE = "voxceleb_CAM++.onnx";
@@ -6396,6 +6460,9 @@ var init_speaker_embedding_runtime = __esm({
6396
6460
  TORCHAUDIO_VERSION = "2.2.0";
6397
6461
  TORCHAUDIO_WHEEL = "https://files.pythonhosted.org/packages/45/a5/74d8a03fdf47cf89e9a2f6c58a65ffe4b392e8cfa503f148baec43377f24/torchaudio-2.2.0-cp310-cp310-manylinux2014_aarch64.whl";
6398
6462
  TORCHAUDIO_WHEEL_SHA256 = "d4ea094b8721a361982db062ee993f2a6f71dfe16f62a84f8900b2364f33a2e4";
6463
+ TYPING_EXTENSIONS_VERSION = "4.10.0";
6464
+ TYPING_EXTENSIONS_WHEEL = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl";
6465
+ TYPING_EXTENSIONS_WHEEL_SHA256 = "69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475";
6399
6466
  JETPACK_TORCH_ABI = "2.2";
6400
6467
  JETPACK_CUDA_VERSION = "12.2";
6401
6468
  SETUP_TIMEOUT_MS3 = 10 * 6e4;
@@ -6405,6 +6472,15 @@ var init_speaker_embedding_runtime = __esm({
6405
6472
  WESPEAKER_CAMPP_MODEL_REVISION = MODEL_REVISION2;
6406
6473
  WESPEAKER_CAMPP_ONNXRUNTIME_VERSION = ONNXRUNTIME_VERSION;
6407
6474
  WESPEAKER_CAMPP_EMBEDDING_SET_SLUG = "speaker-identity-wespeaker-voxceleb-campplus-acf623ad8ca746e50baa432255cf8fc57c669c45-fbank80-cmn-fullclip-l2";
6475
+ SPEAKER_SUPPORT_WHEELS = [
6476
+ {
6477
+ distribution: "typing_extensions",
6478
+ importName: "typing_extensions",
6479
+ version: TYPING_EXTENSIONS_VERSION,
6480
+ source: TYPING_EXTENSIONS_WHEEL,
6481
+ digest: TYPING_EXTENSIONS_WHEEL_SHA256
6482
+ }
6483
+ ];
6408
6484
  state3 = {
6409
6485
  setup: null,
6410
6486
  start: null,
@@ -688266,9 +688342,12 @@ __export(listen_exports, {
688266
688342
  getListenEngine: () => getListenEngine,
688267
688343
  getListenLiveState: () => getListenLiveState,
688268
688344
  isAudioPath: () => isAudioPath,
688345
+ isEggReSpeakerPulseSource: () => isEggReSpeakerPulseSource,
688346
+ isKnownVirtualPulseRemap: () => isKnownVirtualPulseRemap,
688269
688347
  isTranscribablePath: () => isTranscribablePath,
688270
688348
  isVideoPath: () => isVideoPath,
688271
688349
  resolveAsrConsensusModel: () => resolveAsrConsensusModel,
688350
+ selectPreferredPulseMicSource: () => selectPreferredPulseMicSource,
688272
688351
  transcribeFileViaWhisper: () => transcribeFileViaWhisper,
688273
688352
  waitForTranscribeCli: () => waitForTranscribeCli
688274
688353
  });
@@ -688351,10 +688430,30 @@ function renderMicSpectrum(samples) {
688351
688430
  }
688352
688431
  return bands.join("");
688353
688432
  }
688433
+ function isEggReSpeakerPulseSource(source) {
688434
+ return source.channels >= 6 && /(?:^|:)alsa_input\.usb-SEEED_ReSpeaker_4_Mic_Array__UAC1\.0_-00\.multichannel-input$/i.test(source.name);
688435
+ }
688436
+ function isKnownVirtualPulseRemap(sourceName) {
688437
+ const name10 = String(sourceName ?? "").replace(/^pulse:/i, "");
688438
+ return /^nx_remapped_out(?:[._-].*)?$/i.test(name10);
688439
+ }
688440
+ function selectPreferredPulseMicSource(sources) {
688441
+ const candidates = sources.filter((source) => !/\.monitor$/i.test(source.name));
688442
+ const rank = (source) => {
688443
+ let score = 0;
688444
+ if (isEggReSpeakerPulseSource(source)) score -= 1e3;
688445
+ if (isKnownVirtualPulseRemap(source.name)) score += 100;
688446
+ if (source.state === "RUNNING") score -= 20;
688447
+ if (source.state === "SUSPENDED") score += 5;
688448
+ if (/usb|mic|array|respeaker|seeed/i.test(source.name)) score -= 10;
688449
+ return score;
688450
+ };
688451
+ return [...candidates].sort((a2, b) => rank(a2) - rank(b))[0];
688452
+ }
688354
688453
  async function resolveMicSource() {
688355
688454
  const configured = String(process.env["OMNIUS_MIC_DEVICE"] ?? "").trim();
688356
688455
  if (configured.startsWith("hw:") || configured.startsWith("plughw:")) {
688357
- return { alsaDevice: configured, label: configured };
688456
+ return { alsaDevice: configured, sourceKind: "configured-alsa", label: configured };
688358
688457
  }
688359
688458
  const configuredPulse = configured.startsWith("pulse:") ? configured.slice("pulse:".length) : configured || void 0;
688360
688459
  let sources = [];
@@ -688380,21 +688479,19 @@ async function resolveMicSource() {
688380
688479
  return {
688381
688480
  pulseSource: configuredPulse,
688382
688481
  channels: match?.channels,
688482
+ sourceKind: "configured-pulse",
688383
688483
  label: `pulse:${configuredPulse}`
688384
688484
  };
688385
688485
  }
688386
- const candidates = sources.filter((s2) => !/\.monitor$/i.test(s2.name));
688387
- if (candidates.length === 0) return null;
688388
- const rank = (s2) => {
688389
- let score = 0;
688390
- if (s2.state === "RUNNING") score -= 20;
688391
- if (s2.state === "SUSPENDED") score += 5;
688392
- if (/usb|mic|array|respeaker|seeed/i.test(s2.name)) score -= 10;
688393
- return score;
688486
+ const best = selectPreferredPulseMicSource(sources);
688487
+ if (!best) return null;
688488
+ const isReSpeaker = isEggReSpeakerPulseSource(best);
688489
+ return {
688490
+ pulseSource: best.name,
688491
+ channels: best.channels,
688492
+ sourceKind: isReSpeaker ? "respeaker-usb" : "pulse-auto",
688493
+ label: isReSpeaker ? `pulse:${best.name} (ReSpeaker physical 6ch; channel 0)` : `pulse:${best.name}`
688394
688494
  };
688395
- candidates.sort((a2, b) => rank(a2) - rank(b));
688396
- const best = candidates[0];
688397
- return { pulseSource: best.name, channels: best.channels, label: `pulse:${best.name}` };
688398
688495
  }
688399
688496
  async function ensureSourceCaptureVolume(source) {
688400
688497
  try {
@@ -688431,7 +688528,10 @@ async function findMicCaptureCommand() {
688431
688528
  return {
688432
688529
  cmd: "arecord",
688433
688530
  args: ["-D", resolved.alsaDevice, "-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"],
688434
- device: resolved.alsaDevice
688531
+ device: resolved.alsaDevice,
688532
+ sourceKind: resolved.sourceKind,
688533
+ sourceChannels: null,
688534
+ selectedChannel: null
688435
688535
  };
688436
688536
  }
688437
688537
  if (resolved?.pulseSource && await commandExists2("ffmpeg")) {
@@ -688455,14 +688555,20 @@ async function findMicCaptureCommand() {
688455
688555
  "quiet",
688456
688556
  "pipe:1"
688457
688557
  ],
688458
- device: resolved.label
688558
+ device: resolved.label,
688559
+ sourceKind: resolved.sourceKind,
688560
+ sourceChannels: resolved.channels ?? null,
688561
+ selectedChannel: (resolved.channels ?? 1) > 2 ? 0 : null
688459
688562
  };
688460
688563
  }
688461
688564
  if (await commandExists2("arecord")) {
688462
688565
  return {
688463
688566
  cmd: "arecord",
688464
688567
  args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"],
688465
- device: "default (arecord)"
688568
+ device: "default (arecord)",
688569
+ sourceKind: "fallback",
688570
+ sourceChannels: null,
688571
+ selectedChannel: null
688466
688572
  };
688467
688573
  }
688468
688574
  }
@@ -688484,7 +688590,10 @@ async function findMicCaptureCommand() {
688484
688590
  "signed-integer",
688485
688591
  "-"
688486
688592
  ],
688487
- device: "default (sox)"
688593
+ device: "default (sox)",
688594
+ sourceKind: "fallback",
688595
+ sourceChannels: null,
688596
+ selectedChannel: null
688488
688597
  };
688489
688598
  }
688490
688599
  }
@@ -688507,7 +688616,10 @@ async function findMicCaptureCommand() {
688507
688616
  "quiet",
688508
688617
  "pipe:1"
688509
688618
  ],
688510
- device: "pulse:default"
688619
+ device: "pulse:default",
688620
+ sourceKind: "fallback",
688621
+ sourceChannels: null,
688622
+ selectedChannel: null
688511
688623
  };
688512
688624
  } else if (platform13 === "darwin") {
688513
688625
  return {
@@ -688527,7 +688639,10 @@ async function findMicCaptureCommand() {
688527
688639
  "quiet",
688528
688640
  "pipe:1"
688529
688641
  ],
688530
- device: "avfoundation:0"
688642
+ device: "avfoundation:0",
688643
+ sourceKind: "fallback",
688644
+ sourceChannels: null,
688645
+ selectedChannel: null
688531
688646
  };
688532
688647
  }
688533
688648
  }
@@ -688851,6 +688966,9 @@ var init_listen = __esm({
688851
688966
  backend: "",
688852
688967
  model: "",
688853
688968
  micDevice: "",
688969
+ micSourceKind: "unknown",
688970
+ micSourceChannels: null,
688971
+ micSelectedChannel: null,
688854
688972
  micLevelDb: null,
688855
688973
  noiseFloorDb: null,
688856
688974
  speechActive: false,
@@ -689284,7 +689402,12 @@ ${text3}`.slice(-2e3);
689284
689402
  stdio: ["pipe", "pipe", "pipe"],
689285
689403
  env: { ...process.env }
689286
689404
  });
689287
- updateListenLiveState({ micDevice: micCmd.device });
689405
+ updateListenLiveState({
689406
+ micDevice: micCmd.device,
689407
+ micSourceKind: micCmd.sourceKind,
689408
+ micSourceChannels: micCmd.sourceChannels,
689409
+ micSelectedChannel: micCmd.selectedChannel
689410
+ });
689288
689411
  this.micProcess.stdout?.on("data", (chunk) => {
689289
689412
  this.meterMicChunk(chunk);
689290
689413
  if (this.active && !this.paused && this.liveTranscriber) {
@@ -692573,14 +692696,28 @@ function isAudioOutputMonitorDevice(device2) {
692573
692696
  if (!device2) return false;
692574
692697
  return isAudioOutputMonitorId(device2.id) || isAudioOutputMonitorId(device2.label) || isAudioOutputMonitorId(device2.detail);
692575
692698
  }
692699
+ function isEggReSpeakerLiveInput(device2) {
692700
+ if (!device2?.id.startsWith("pulse:")) return false;
692701
+ return isEggReSpeakerPulseSource({
692702
+ name: device2.id.slice("pulse:".length),
692703
+ channels: liveDeviceChannels(device2) ?? 0
692704
+ });
692705
+ }
692706
+ function shouldReplaceStaleVirtualAudioSelection(configured, usable) {
692707
+ return Boolean(configured && isKnownVirtualPulseRemap(configured) && usable.some(isEggReSpeakerLiveInput));
692708
+ }
692576
692709
  function preferredLiveAudioInputId(devices, configured) {
692577
692710
  const usable = devices.filter((device2) => device2.id && !isAudioOutputMonitorDevice(device2));
692578
- if (configured && usable.some((device2) => device2.id === configured)) return configured;
692711
+ if (configured && usable.some((device2) => device2.id === configured) && !shouldReplaceStaleVirtualAudioSelection(configured, usable)) {
692712
+ return configured;
692713
+ }
692579
692714
  return rankLiveAudioInputDevices(devices, configured)[0]?.id ?? firstDeviceId(devices);
692580
692715
  }
692581
692716
  function liveAudioDeviceRank(device2, configured) {
692582
692717
  let rank = 0;
692583
692718
  if (device2.id === configured) rank -= 40;
692719
+ if (isEggReSpeakerLiveInput(device2)) rank -= 1e3;
692720
+ if (isKnownVirtualPulseRemap(device2.id)) rank += 100;
692584
692721
  if (isAudioOutputMonitorDevice(device2)) rank += 500;
692585
692722
  if (device2.source === "pulse" || device2.source === "pipewire") rank -= 20;
692586
692723
  if (device2.source === "alsa") rank -= 10;
@@ -693202,7 +693339,10 @@ var init_live_sensors = __esm({
693202
693339
  };
693203
693340
  if (!this.config.selectedCamera) this.config.selectedCamera = firstDeviceId(video);
693204
693341
  this.config.cameraStreams = this.reconcileCameraStreams(video);
693205
- if (!this.config.selectedAudioInput) this.config.selectedAudioInput = preferredLiveAudioInputId(inputs.devices);
693342
+ const preferredAudioInput = preferredLiveAudioInputId(inputs.devices, this.config.selectedAudioInput);
693343
+ if (!this.config.selectedAudioInput || shouldReplaceStaleVirtualAudioSelection(this.config.selectedAudioInput, inputs.devices)) {
693344
+ this.config.selectedAudioInput = preferredAudioInput;
693345
+ }
693206
693346
  if (!this.config.selectedAudioOutput) this.config.selectedAudioOutput = firstDeviceId(outputs.devices);
693207
693347
  this.persist();
693208
693348
  return this.devices;
@@ -792531,6 +792671,10 @@ function getRuntimeStatus() {
792531
792671
  asrBackend: asrEngineId === "vibevoice-transformers" ? "vibevoice-transformers" : listenState.backend,
792532
792672
  asrPhase: asrEngineId === "vibevoice-transformers" ? vibePhase : listenState.phase,
792533
792673
  asrReady: asrEngineId === "vibevoice-transformers" ? vibe.active : Boolean(_listenEngine?.isActive),
792674
+ micDevice: listenState.micDevice || null,
792675
+ micSourceKind: listenState.micSourceKind,
792676
+ micSourceChannels: listenState.micSourceChannels,
792677
+ micSelectedChannel: listenState.micSelectedChannel,
792534
792678
  clientCount: _clients2.size,
792535
792679
  loadedAt: _loadedAt,
792536
792680
  lastError: _lastError
@@ -828308,7 +828452,7 @@ function getOpenApiSpec() {
828308
828452
  "/v1/agents": { get: { summary: "List agent types", tags: ["Tools"], responses: { 200: { description: "Agent type registry" } } } },
828309
828453
  "/v1/engines": { get: { summary: "List long-running engines", tags: ["Engines"], responses: { 200: { description: "Engine status + state files" } } } },
828310
828454
  // ───── Voice / Audio surface (live) ─────
828311
- "/v1/voice/state": { get: { summary: "Voice runtime status (engine load state, active model, current clone ref, client count)", tags: ["Voice"], responses: { 200: { description: "Runtime status snapshot" } } } },
828455
+ "/v1/voice/state": { get: { summary: "Voice runtime status (engine/model state plus actual selected microphone source and channel provenance)", tags: ["Voice"], responses: { 200: { description: "Runtime status snapshot" } } } },
828312
828456
  "/v1/voice/start": { post: { summary: "Enable and warm the daemon voice runtime; optional body {modelId|model|voice}", tags: ["Voice"], responses: { 200: { description: "Voice enabled and ready" }, 400: { description: "Unknown model" }, 409: { description: "Model disabled by configuration" }, 500: { description: "Warmup failed" } } } },
828313
828457
  "/v1/voice/stop": { post: { summary: "Pause daemon voice input immediately (TTS models remain warm)", tags: ["Voice"], responses: { 200: { description: "Voice input paused" }, 500: { description: "Stop failed" } } } },
828314
828458
  "/v1/voice/models": { get: { summary: "List TTS voice models with backend metadata and managed readiness", tags: ["Voice"], responses: { 200: { description: "Voice model list, active selection, and Voxtral pull/deploy state" } } } },
@@ -828436,7 +828580,7 @@ function getOpenApiSpec() {
828436
828580
  post: {
828437
828581
  summary: "Provision and activate one role-typed audio embedding runtime",
828438
828582
  tags: ["Audio"],
828439
- description: "Admin-only. Requires kind=acoustic|speaker|semantic in the query (canonical) or JSON body. acoustic reuses the pinned JetPack YAMNet/TensorRT setup; speaker installs the isolated CPU-only WeSpeaker CAM++ ONNX Runtime and pinned model, then installs only the checksummed CPython 3.10/aarch64 Torchaudio 2.2.0 wheel into ~/.omnius/runtimes/audio/speaker/venv with --no-deps/--no-index. It retains --system-site-packages and links the selected OMNIUS_AUDIO_PYTHON JetPack Torch 2.2/CUDA 12.2 provider without writing to it; setup proves the Torch/Torchaudio ABI and CPU kaldi.fbank before readiness. An operator may replace that wheel only by supplying both OMNIUS_SPEAKER_TORCHAUDIO_WHEEL and OMNIUS_SPEAKER_TORCHAUDIO_WHEEL_SHA256. semantic installs the isolated JetPack CUDA CLAP dependencies and pinned model. This is the only REST operation allowed to provision. It activates and warms only the requested role worker; no role is substituted for another.",
828583
+ description: "Admin-only. Requires kind=acoustic|speaker|semantic in the query (canonical) or JSON body. acoustic reuses the pinned JetPack YAMNet/TensorRT setup; speaker installs the isolated CPU-only WeSpeaker CAM++ ONNX Runtime and pinned model, then installs only checksummed wheels into ~/.omnius/runtimes/audio/speaker/venv: CPython 3.10/aarch64 Torchaudio 2.2.0 and the self-contained typing_extensions support dependency, each with --no-deps/--no-index. It retains --system-site-packages and links the selected OMNIUS_AUDIO_PYTHON JetPack Torch 2.2/CUDA 12.2 provider without writing to it; setup proves the Torch/Torchaudio ABI and CPU kaldi.fbank before readiness. An operator may replace the Torchaudio wheel only by supplying both OMNIUS_SPEAKER_TORCHAUDIO_WHEEL and OMNIUS_SPEAKER_TORCHAUDIO_WHEEL_SHA256. semantic installs the isolated JetPack CUDA CLAP dependencies and pinned model. This is the only REST operation allowed to provision. It activates and warms only the requested role worker; no role is substituted for another.",
828440
828584
  parameters: [{ name: "kind", in: "query", required: false, schema: { type: "string", enum: ["acoustic", "speaker", "semantic"] }, description: "Canonical required role selector; JSON body.kind is accepted for compatibility." }],
828441
828585
  requestBody: { required: false, content: { "application/json": { schema: { type: "object", properties: { kind: { type: "string", enum: ["acoustic", "speaker", "semantic"] } } } } } },
828442
828586
  responses: { 200: { description: "Requested role runtime provisioned and warm." }, 202: { description: "Provisioning finished but requested role did not prove warm; poll its health URL." }, 400: { description: "kind is missing or invalid." }, 403: { description: "Admin scope required." }, 500: { description: "Role-specific setup/preflight failed." } }
@@ -830030,6 +830174,71 @@ function getBackendTimeoutMs(perRequestSeconds) {
830030
830174
  }
830031
830175
  return BACKEND_TIMEOUT_DEFAULT_MS;
830032
830176
  }
830177
+ function getAgentLoopToolTimeoutMs() {
830178
+ const configured = Number(process.env["OMNIUS_AGENT_LOOP_TOOL_TIMEOUT_MS"]);
830179
+ if (!Number.isFinite(configured) || configured <= 0) {
830180
+ return AGENT_LOOP_TOOL_TIMEOUT_DEFAULT_MS;
830181
+ }
830182
+ return Math.max(1e3, Math.min(Math.floor(configured), AGENT_LOOP_TOOL_TIMEOUT_MAX_MS));
830183
+ }
830184
+ function cancelAgentLoopTool(tool) {
830185
+ if (!tool || typeof tool.cancel !== "function" || cancelledAgentLoopTools.has(tool)) {
830186
+ return;
830187
+ }
830188
+ cancelledAgentLoopTools.add(tool);
830189
+ try {
830190
+ const cancelled = tool.cancel();
830191
+ if (cancelled && typeof cancelled.then === "function") {
830192
+ void Promise.resolve(cancelled).catch(() => void 0);
830193
+ }
830194
+ } catch {
830195
+ }
830196
+ }
830197
+ async function executeAgentLoopToolBounded(tool, args, timeoutMs, clientDisconnect) {
830198
+ const startedAt2 = performance.now();
830199
+ const execution = Promise.resolve().then(() => tool.execute(args)).then(
830200
+ (result) => ({ kind: "result", result }),
830201
+ (error) => ({ kind: "error", error })
830202
+ );
830203
+ let timer;
830204
+ try {
830205
+ const outcome = await Promise.race([
830206
+ execution,
830207
+ new Promise((resolveTimeout) => {
830208
+ timer = setTimeout(() => resolveTimeout({ kind: "timeout" }), timeoutMs);
830209
+ timer.unref();
830210
+ }),
830211
+ clientDisconnect.then(() => ({ kind: "client_disconnected" }))
830212
+ ]);
830213
+ if (outcome.kind === "result") {
830214
+ return { result: outcome.result, clientDisconnected: false };
830215
+ }
830216
+ if (outcome.kind === "error") throw outcome.error;
830217
+ cancelAgentLoopTool(tool);
830218
+ if (outcome.kind === "client_disconnected") {
830219
+ return {
830220
+ result: {
830221
+ success: false,
830222
+ output: "",
830223
+ error: "agent_loop_client_disconnected",
830224
+ durationMs: performance.now() - startedAt2
830225
+ },
830226
+ clientDisconnected: true
830227
+ };
830228
+ }
830229
+ return {
830230
+ result: {
830231
+ success: false,
830232
+ output: "",
830233
+ error: `agent_loop_tool_timeout: daemon tool exceeded ${timeoutMs}ms`,
830234
+ durationMs: performance.now() - startedAt2
830235
+ },
830236
+ clientDisconnected: false
830237
+ };
830238
+ } finally {
830239
+ if (timer) clearTimeout(timer);
830240
+ }
830241
+ }
830033
830242
  function getModelListTimeoutMs() {
830034
830243
  const envS = process.env["OMNIUS_MODEL_LIST_TIMEOUT_S"];
830035
830244
  if (envS) {
@@ -832379,361 +832588,447 @@ async function handleApiTags(res) {
832379
832588
  }
832380
832589
  async function runAgentLoopChatCompletions(opts) {
832381
832590
  const { req: req3, res, ollamaUrl, requestBody, perReqTimeoutS } = opts;
832382
- const startMs = Date.now();
832383
- const reqTimeoutMs = getBackendTimeoutMs(perReqTimeoutS);
832384
- const totalDeadline = startMs + (perReqTimeoutS && perReqTimeoutS > 0 ? Math.min(perReqTimeoutS * 1e3, BACKEND_TIMEOUT_MAX_MS) : 30 * 60 * 1e3);
832385
- const model = requestBody["model"] || "unknown";
832386
- const route = resolveModelEndpoint(model);
832387
- const targetUrl = route?.endpoint.url ?? ollamaUrl;
832388
- const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
832389
- const originalModel = route?.originalId ?? model;
832390
- const maxTurns = typeof requestBody["max_turns"] === "number" ? Math.max(1, Math.min(64, requestBody["max_turns"])) : 8;
832391
- const remoteIp = (req3.socket?.remoteAddress || "").replace(/^::ffff:/, "");
832392
- const origin = /^(127\.\d+\.\d+\.\d+|::1|localhost)$/.test(remoteIp) ? "loopback" : "remote";
832393
- const reqAuth = req3;
832394
- const scope = reqAuth._authScope ?? (origin === "loopback" ? "admin" : "read");
832395
- const profileName = typeof requestBody["profile"] === "string" ? requestBody["profile"] : typeof req3.headers["x-tool-profile"] === "string" ? req3.headers["x-tool-profile"] : req3._authProfile;
832396
- const activeProfileMeta = profileName ? loadProfileWithMeta(
832397
- profileName,
832398
- typeof req3.headers["x-profile-password"] === "string" ? req3.headers["x-profile-password"] : void 0,
832399
- process.cwd()
832400
- ) : null;
832401
- if (profileName && !activeProfileMeta) {
832402
- jsonResponse(res, 400, {
832403
- error: "Profile not found or wrong password",
832404
- profile: profileName,
832405
- search_order: [
832406
- "preset",
832407
- `${process.cwd()}/.omnius/profiles/${profileName}.json`,
832408
- "~/.omnius/profiles"
832409
- ]
832410
- });
832411
- return;
832412
- }
832413
- const execMod = await Promise.resolve().then(() => (init_dist5(), dist_exports2)).catch(() => null);
832414
- if (!execMod) {
832415
- jsonResponse(res, 500, { error: "Execution module unavailable" });
832416
- return;
832417
- }
832418
- const classify2 = execMod.classifyTool;
832419
- const canInvoke = execMod.canInvokeTool;
832420
- const daemonTools = /* @__PURE__ */ new Map();
832421
- for (const [classKey, value2] of Object.entries(execMod)) {
832422
- if (typeof value2 !== "function") continue;
832423
- const proto = value2.prototype;
832424
- if (!proto || typeof proto.execute !== "function") continue;
832425
- let probe = null;
832426
- try {
832427
- probe = new value2();
832428
- } catch {
832591
+ let activeTool = null;
832592
+ let clientDisconnected = false;
832593
+ let resolveClientDisconnect;
832594
+ const clientDisconnect = new Promise((resolveDisconnect) => {
832595
+ resolveClientDisconnect = resolveDisconnect;
832596
+ });
832597
+ const cancelActiveTool = () => cancelAgentLoopTool(activeTool);
832598
+ const markClientDisconnected = () => {
832599
+ if (clientDisconnected) return;
832600
+ clientDisconnected = true;
832601
+ cancelActiveTool();
832602
+ resolveClientDisconnect();
832603
+ };
832604
+ const isClientDisconnected = () => {
832605
+ if (!clientDisconnected && (req3.aborted || res.destroyed && !res.writableEnded)) {
832606
+ markClientDisconnected();
832607
+ }
832608
+ return clientDisconnected;
832609
+ };
832610
+ const onRequestAborted = () => markClientDisconnected();
832611
+ const onRequestClose = () => {
832612
+ if (!req3.complete && !res.writableEnded) markClientDisconnected();
832613
+ };
832614
+ const onResponseClose = () => {
832615
+ if (!res.writableEnded) markClientDisconnected();
832616
+ };
832617
+ const onRequestError = () => markClientDisconnected();
832618
+ const onResponseError = () => markClientDisconnected();
832619
+ req3.once("aborted", onRequestAborted);
832620
+ req3.once("close", onRequestClose);
832621
+ req3.once("error", onRequestError);
832622
+ res.once("close", onResponseClose);
832623
+ res.once("error", onResponseError);
832624
+ try {
832625
+ const startMs = Date.now();
832626
+ const reqTimeoutMs = getBackendTimeoutMs(perReqTimeoutS);
832627
+ const totalDeadline = startMs + AGENT_LOOP_TOTAL_MAX_MS;
832628
+ const model = requestBody["model"] || "unknown";
832629
+ const route = resolveModelEndpoint(model);
832630
+ const targetUrl = route?.endpoint.url ?? ollamaUrl;
832631
+ const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
832632
+ const originalModel = route?.originalId ?? model;
832633
+ const maxTurns = typeof requestBody["max_turns"] === "number" ? Math.max(1, Math.min(64, requestBody["max_turns"])) : 8;
832634
+ const remoteIp = (req3.socket?.remoteAddress || "").replace(/^::ffff:/, "");
832635
+ const origin = /^(127\.\d+\.\d+\.\d+|::1|localhost)$/.test(remoteIp) ? "loopback" : "remote";
832636
+ const reqAuth = req3;
832637
+ const scope = reqAuth._authScope ?? (origin === "loopback" ? "admin" : "read");
832638
+ const profileName = typeof requestBody["profile"] === "string" ? requestBody["profile"] : typeof req3.headers["x-tool-profile"] === "string" ? req3.headers["x-tool-profile"] : req3._authProfile;
832639
+ const activeProfileMeta = profileName ? loadProfileWithMeta(
832640
+ profileName,
832641
+ typeof req3.headers["x-profile-password"] === "string" ? req3.headers["x-profile-password"] : void 0,
832642
+ process.cwd()
832643
+ ) : null;
832644
+ if (profileName && !activeProfileMeta) {
832645
+ jsonResponse(res, 400, {
832646
+ error: "Profile not found or wrong password",
832647
+ profile: profileName,
832648
+ search_order: [
832649
+ "preset",
832650
+ `${process.cwd()}/.omnius/profiles/${profileName}.json`,
832651
+ "~/.omnius/profiles"
832652
+ ]
832653
+ });
832654
+ return;
832655
+ }
832656
+ const execMod = await Promise.resolve().then(() => (init_dist5(), dist_exports2)).catch(() => null);
832657
+ if (isClientDisconnected()) return;
832658
+ if (!execMod) {
832659
+ jsonResponse(res, 500, { error: "Execution module unavailable" });
832660
+ return;
832661
+ }
832662
+ const classify2 = execMod.classifyTool;
832663
+ const canInvoke = execMod.canInvokeTool;
832664
+ const daemonTools = /* @__PURE__ */ new Map();
832665
+ for (const [classKey, value2] of Object.entries(execMod)) {
832666
+ if (typeof value2 !== "function") continue;
832667
+ const proto = value2.prototype;
832668
+ if (!proto || typeof proto.execute !== "function") continue;
832669
+ let probe = null;
832429
832670
  try {
832430
- probe = new value2(process.cwd());
832671
+ probe = new value2();
832431
832672
  } catch {
832432
- probe = null;
832673
+ try {
832674
+ probe = new value2(process.cwd());
832675
+ } catch {
832676
+ probe = null;
832677
+ }
832678
+ }
832679
+ if (probe?.name && typeof probe.name === "string") {
832680
+ daemonTools.set(probe.name, { ToolClass: value2, classKey });
832433
832681
  }
832434
832682
  }
832435
- if (probe?.name && typeof probe.name === "string") {
832436
- daemonTools.set(probe.name, { ToolClass: value2, classKey });
832437
- }
832438
- }
832439
- const includeDaemonTools = Array.isArray(requestBody["include_daemon_tools"]) ? requestBody["include_daemon_tools"].filter(
832440
- (s2) => typeof s2 === "string"
832441
- ) : [];
832442
- const advertisedDaemonNames = /* @__PURE__ */ new Set();
832443
- if (includeDaemonTools.length > 0) {
832444
- for (const [toolName, { ToolClass: _T }] of daemonTools.entries()) {
832445
- void _T;
832446
- const sec = classify2(toolName);
832447
- if (!sec) continue;
832448
- if (activeProfileMeta && !isToolAllowed(activeProfileMeta.profile, toolName))
832449
- continue;
832450
- if (!includeDaemonTools.includes(sec.requires_scope)) continue;
832451
- if (canInvoke({ toolName, origin, scope }) !== null) continue;
832452
- advertisedDaemonNames.add(toolName);
832683
+ const includeDaemonTools = Array.isArray(requestBody["include_daemon_tools"]) ? requestBody["include_daemon_tools"].filter(
832684
+ (s2) => typeof s2 === "string"
832685
+ ) : [];
832686
+ const advertisedDaemonNames = /* @__PURE__ */ new Set();
832687
+ if (includeDaemonTools.length > 0) {
832688
+ for (const [toolName, { ToolClass: _T }] of daemonTools.entries()) {
832689
+ void _T;
832690
+ const sec = classify2(toolName);
832691
+ if (!sec) continue;
832692
+ if (activeProfileMeta && !isToolAllowed(activeProfileMeta.profile, toolName))
832693
+ continue;
832694
+ if (!includeDaemonTools.includes(sec.requires_scope)) continue;
832695
+ if (canInvoke({ toolName, origin, scope }) !== null) continue;
832696
+ advertisedDaemonNames.add(toolName);
832697
+ }
832453
832698
  }
832454
- }
832455
- const callerTools = Array.isArray(requestBody["tools"]) ? requestBody["tools"].filter(
832456
- (t2) => t2?.type === "function" && typeof t2?.function?.name === "string"
832457
- ) : [];
832458
- const callerToolNames = new Set(callerTools.map((t2) => t2.function.name));
832459
- const daemonToolEntries = [];
832460
- for (const name10 of advertisedDaemonNames) {
832461
- if (callerToolNames.has(name10)) continue;
832462
- const meta = daemonTools.get(name10);
832463
- if (!meta) continue;
832464
- let inst = null;
832465
- try {
832466
- inst = new meta.ToolClass();
832467
- } catch {
832699
+ const callerTools = Array.isArray(requestBody["tools"]) ? requestBody["tools"].filter(
832700
+ (t2) => t2?.type === "function" && typeof t2?.function?.name === "string"
832701
+ ) : [];
832702
+ const callerToolNames = new Set(callerTools.map((t2) => t2.function.name));
832703
+ const daemonToolEntries = [];
832704
+ for (const name10 of advertisedDaemonNames) {
832705
+ if (callerToolNames.has(name10)) continue;
832706
+ const meta = daemonTools.get(name10);
832707
+ if (!meta) continue;
832708
+ let inst = null;
832468
832709
  try {
832469
- inst = new meta.ToolClass(process.cwd());
832710
+ inst = new meta.ToolClass();
832470
832711
  } catch {
832471
- inst = null;
832712
+ try {
832713
+ inst = new meta.ToolClass(process.cwd());
832714
+ } catch {
832715
+ inst = null;
832716
+ }
832472
832717
  }
832718
+ if (!inst) continue;
832719
+ daemonToolEntries.push({
832720
+ type: "function",
832721
+ function: {
832722
+ name: name10,
832723
+ description: typeof inst.description === "string" ? inst.description : "",
832724
+ parameters: inst.parameters ?? { type: "object", properties: {} }
832725
+ }
832726
+ });
832473
832727
  }
832474
- if (!inst) continue;
832475
- daemonToolEntries.push({
832476
- type: "function",
832477
- function: {
832478
- name: name10,
832479
- description: typeof inst.description === "string" ? inst.description : "",
832480
- parameters: inst.parameters ?? { type: "object", properties: {} }
832481
- }
832482
- });
832483
- }
832484
- const mergedTools = [...callerTools, ...daemonToolEntries];
832485
- const messages2 = Array.isArray(requestBody["messages"]) ? requestBody["messages"].slice() : [];
832486
- const promptTemplate = typeof requestBody["prompt_template"] === "string" ? requestBody["prompt_template"] : null;
832487
- if (promptTemplate === "factual-first" && advertisedDaemonNames.has("web_search")) {
832488
- const SYSTEM_FACTUAL_FIRST = [
832489
- "[POLICY: factual-first]",
832490
- "For any user question that asks for a fact, statistic, current event,",
832491
- "person/place/product detail, or anything you might be tempted to answer",
832492
- "from training data alone — your FIRST tool_call MUST be `web_search`",
832493
- "with a query derived from the user's question. Do NOT answer from",
832494
- "training data. After web_search returns, optionally call `web_fetch`",
832495
- "on the most relevant URL, then synthesize a grounded answer citing",
832496
- "the source. Decline to answer factual questions if web_search is",
832497
- "unavailable."
832498
- ].join(" ");
832499
- const firstSystemIdx = messages2.findIndex((m2) => m2.role === "system");
832500
- if (firstSystemIdx >= 0 && typeof messages2[firstSystemIdx].content === "string") {
832501
- messages2[firstSystemIdx] = {
832502
- ...messages2[firstSystemIdx],
832503
- content: `${SYSTEM_FACTUAL_FIRST}
832728
+ const mergedTools = [...callerTools, ...daemonToolEntries];
832729
+ const forceNoThinkForTools = targetType === "ollama" && mergedTools.length > 0;
832730
+ const messages2 = Array.isArray(requestBody["messages"]) ? requestBody["messages"].slice() : [];
832731
+ const promptTemplate = typeof requestBody["prompt_template"] === "string" ? requestBody["prompt_template"] : null;
832732
+ if (promptTemplate === "factual-first" && advertisedDaemonNames.has("web_search")) {
832733
+ const SYSTEM_FACTUAL_FIRST = [
832734
+ "[POLICY: factual-first]",
832735
+ "For any user question that asks for a fact, statistic, current event,",
832736
+ "person/place/product detail, or anything you might be tempted to answer",
832737
+ "from training data alone — your FIRST tool_call MUST be `web_search`",
832738
+ "with a query derived from the user's question. Do NOT answer from",
832739
+ "training data. After web_search returns, optionally call `web_fetch`",
832740
+ "on the most relevant URL, then synthesize a grounded answer citing",
832741
+ "the source. Decline to answer factual questions if web_search is",
832742
+ "unavailable."
832743
+ ].join(" ");
832744
+ const firstSystemIdx = messages2.findIndex((m2) => m2.role === "system");
832745
+ if (firstSystemIdx >= 0 && typeof messages2[firstSystemIdx].content === "string") {
832746
+ messages2[firstSystemIdx] = {
832747
+ ...messages2[firstSystemIdx],
832748
+ content: `${SYSTEM_FACTUAL_FIRST}
832504
832749
 
832505
832750
  ${messages2[firstSystemIdx].content}`
832506
- };
832507
- } else {
832508
- messages2.unshift({ role: "system", content: SYSTEM_FACTUAL_FIRST });
832509
- }
832510
- }
832511
- const chatId = `chatcmpl-${randomBytes30(12).toString("hex")}`;
832512
- const turnsLog = [];
832513
- for (let turn = 1; turn <= maxTurns; turn++) {
832514
- if (Date.now() > totalDeadline) {
832515
- jsonResponse(res, 504, {
832516
- error: "agent_loop timed out",
832517
- turn,
832518
- elapsed_ms: Date.now() - startMs,
832519
- timeout_s: perReqTimeoutS ?? null
832520
- });
832521
- return;
832751
+ };
832752
+ } else {
832753
+ messages2.unshift({ role: "system", content: SYSTEM_FACTUAL_FIRST });
832754
+ }
832522
832755
  }
832523
- const turnBody = {
832524
- ...requestBody,
832525
- model: originalModel,
832526
- messages: messages2,
832527
- tools: mergedTools.length > 0 ? mergedTools : void 0,
832528
- stream: false,
832529
- // Strip our own loop-control fields so they don't confuse the backend
832530
- agent_loop: void 0,
832531
- include_daemon_tools: void 0,
832532
- max_turns: void 0,
832533
- timeout_s: void 0,
832534
- realtime: void 0,
832535
- realtime_options: void 0,
832536
- realtime_max_history_messages: void 0,
832537
- realtime_max_tokens: void 0
832538
- };
832539
- for (const k of Object.keys(turnBody))
832540
- if (turnBody[k] === void 0) delete turnBody[k];
832541
- let parsed;
832542
- try {
832543
- const path16 = targetType === "vllm" || targetType === "openai" ? "/v1/chat/completions" : "/v1/chat/completions";
832544
- const result = await ollamaRequest(
832545
- targetUrl,
832546
- path16,
832547
- "POST",
832548
- JSON.stringify(turnBody),
832549
- reqTimeoutMs,
832550
- route?.endpoint
832551
- );
832552
- if (result.status !== 200) {
832553
- jsonResponse(res, result.status, {
832554
- error: "Backend request failed during agent_loop",
832756
+ const chatId = `chatcmpl-${randomBytes30(12).toString("hex")}`;
832757
+ const turnsLog = [];
832758
+ for (let turn = 1; turn <= maxTurns; turn++) {
832759
+ if (isClientDisconnected()) return;
832760
+ if (Date.now() > totalDeadline) {
832761
+ jsonResponse(res, 504, {
832762
+ error: "agent_loop timed out",
832555
832763
  turn,
832556
- details: result.body.slice(0, 500)
832764
+ elapsed_ms: Date.now() - startMs,
832765
+ timeout_s: perReqTimeoutS ?? null
832557
832766
  });
832558
832767
  return;
832559
832768
  }
832560
- parsed = JSON.parse(result.body);
832561
- } catch (err) {
832562
- jsonResponse(res, 502, {
832563
- error: "Backend proxy error during agent_loop",
832564
- message: err instanceof Error ? err.message : String(err),
832565
- turn
832566
- });
832567
- return;
832568
- }
832569
- const choice = parsed?.choices?.[0];
832570
- const message2 = choice?.message || { role: "assistant", content: "" };
832571
- const toolCalls = Array.isArray(message2.tool_calls) ? message2.tool_calls : [];
832572
- if (toolCalls.length === 0) {
832573
- jsonResponse(res, 200, {
832574
- ...parsed,
832575
- id: chatId,
832576
- _agent_loop: {
832577
- turns: turn,
832578
- log: turnsLog,
832579
- done: true,
832580
- reason: "model_returned_content"
832581
- }
832582
- });
832583
- return;
832584
- }
832585
- const daemonCalls = [];
832586
- const clientCalls = [];
832587
- for (const tc of toolCalls) {
832588
- const name10 = tc?.function?.name ?? tc?.name ?? "";
832589
- if (advertisedDaemonNames.has(name10)) daemonCalls.push(tc);
832590
- else clientCalls.push(tc);
832591
- }
832592
- if (clientCalls.length > 0) {
832593
- turnsLog.push({
832594
- turn,
832595
- tool_calls: toolCalls.length,
832596
- daemon_executed: 0,
832597
- client_yielded: clientCalls.length
832598
- });
832599
- jsonResponse(res, 200, {
832600
- ...parsed,
832601
- id: chatId,
832602
- _agent_loop: {
832603
- turns: turn,
832604
- log: turnsLog,
832605
- done: false,
832606
- reason: "client_tools_pending",
832607
- pending_tool_calls: clientCalls.length
832608
- }
832609
- });
832610
- return;
832611
- }
832612
- messages2.push(message2);
832613
- let executed = 0;
832614
- for (const tc of daemonCalls) {
832615
- const name10 = tc?.function?.name ?? tc?.name ?? "";
832616
- const argsRaw = tc?.function?.arguments ?? tc?.arguments ?? "{}";
832617
- let args = {};
832618
- try {
832619
- args = typeof argsRaw === "string" ? JSON.parse(argsRaw) : argsRaw || {};
832620
- } catch {
832621
- args = {};
832769
+ const remainingMs = totalDeadline - Date.now();
832770
+ if (remainingMs <= 0) {
832771
+ jsonResponse(res, 504, {
832772
+ error: "agent_loop timed out",
832773
+ turn,
832774
+ elapsed_ms: Date.now() - startMs,
832775
+ timeout_s: perReqTimeoutS ?? null
832776
+ });
832777
+ return;
832622
832778
  }
832623
- const denial = canInvoke({ toolName: name10, origin, scope });
832624
- if (denial) {
832625
- messages2.push({
832626
- role: "tool",
832627
- tool_call_id: tc.id,
832628
- name: name10,
832629
- content: JSON.stringify({
832630
- error: denial.reason,
832631
- status: denial.status
832632
- })
832779
+ const turnBody = {
832780
+ ...requestBody,
832781
+ model: originalModel,
832782
+ messages: forceNoThinkForTools ? messages2.map((message3) => typeof message3.content === "string" ? { ...message3, content: stripNoThinkPromptDirectives(message3.content) } : message3) : messages2,
832783
+ tools: mergedTools.length > 0 ? mergedTools : void 0,
832784
+ stream: false,
832785
+ ...forceNoThinkForTools ? { think: false } : {},
832786
+ // Strip our own loop-control fields so they don't confuse the backend
832787
+ agent_loop: void 0,
832788
+ include_daemon_tools: void 0,
832789
+ max_turns: void 0,
832790
+ timeout_s: void 0,
832791
+ realtime: void 0,
832792
+ realtime_options: void 0,
832793
+ realtime_max_history_messages: void 0,
832794
+ realtime_max_tokens: void 0
832795
+ };
832796
+ for (const k of Object.keys(turnBody))
832797
+ if (turnBody[k] === void 0) delete turnBody[k];
832798
+ let parsed;
832799
+ try {
832800
+ const path16 = targetType === "vllm" || targetType === "openai" ? "/v1/chat/completions" : "/v1/chat/completions";
832801
+ const result = await ollamaRequest(
832802
+ targetUrl,
832803
+ path16,
832804
+ "POST",
832805
+ JSON.stringify(turnBody),
832806
+ Math.min(reqTimeoutMs, remainingMs),
832807
+ route?.endpoint
832808
+ );
832809
+ if (isClientDisconnected()) return;
832810
+ if (result.status !== 200) {
832811
+ jsonResponse(res, result.status, {
832812
+ error: "Backend request failed during agent_loop",
832813
+ turn,
832814
+ details: result.body.slice(0, 500)
832815
+ });
832816
+ return;
832817
+ }
832818
+ parsed = JSON.parse(result.body);
832819
+ } catch (err) {
832820
+ if (isClientDisconnected()) return;
832821
+ jsonResponse(res, 502, {
832822
+ error: "Backend proxy error during agent_loop",
832823
+ message: err instanceof Error ? err.message : String(err),
832824
+ turn
832633
832825
  });
832634
- continue;
832826
+ return;
832635
832827
  }
832636
- if (activeProfileMeta && !isToolAllowed(activeProfileMeta.profile, name10)) {
832637
- messages2.push({
832638
- role: "tool",
832639
- tool_call_id: tc.id,
832640
- name: name10,
832641
- content: JSON.stringify({
832642
- success: false,
832643
- error: `Tool '${name10}' is denied by profile '${activeProfileMeta.profile.name}'.`,
832644
- active_profile: {
832645
- name: activeProfileMeta.profile.name,
832646
- source: activeProfileMeta.source,
832647
- path: activeProfileMeta.path,
832648
- allowed_tools: allowedToolsForProfile(
832649
- activeProfileMeta.profile,
832650
- daemonTools.keys()
832651
- )
832652
- }
832653
- })
832828
+ const choice = parsed?.choices?.[0];
832829
+ const rawMessage = choice?.message || {};
832830
+ const message2 = {
832831
+ ...rawMessage,
832832
+ role: typeof rawMessage.role === "string" ? rawMessage.role : "assistant",
832833
+ // Tool-only OpenAI/Ollama turns can return null content. Preserve the
832834
+ // tool_calls but normalize content for the next protocol turn.
832835
+ content: typeof rawMessage.content === "string" ? rawMessage.content : ""
832836
+ };
832837
+ const toolCalls = Array.isArray(message2.tool_calls) ? message2.tool_calls : [];
832838
+ if (toolCalls.length === 0) {
832839
+ jsonResponse(res, 200, {
832840
+ ...parsed,
832841
+ id: chatId,
832842
+ _agent_loop: {
832843
+ turns: turn,
832844
+ log: turnsLog,
832845
+ done: true,
832846
+ reason: "model_returned_content"
832847
+ }
832654
832848
  });
832655
- continue;
832849
+ return;
832656
832850
  }
832657
- const meta = daemonTools.get(name10);
832658
- if (!meta) {
832659
- messages2.push({
832660
- role: "tool",
832661
- tool_call_id: tc.id,
832662
- name: name10,
832663
- content: JSON.stringify({ error: `Daemon tool '${name10}' not found` })
832851
+ const daemonCalls = [];
832852
+ const clientCalls = [];
832853
+ for (const tc of toolCalls) {
832854
+ const name10 = tc?.function?.name ?? tc?.name ?? "";
832855
+ if (advertisedDaemonNames.has(name10)) daemonCalls.push(tc);
832856
+ else clientCalls.push(tc);
832857
+ }
832858
+ if (clientCalls.length > 0) {
832859
+ turnsLog.push({
832860
+ turn,
832861
+ tool_calls: toolCalls.length,
832862
+ daemon_executed: 0,
832863
+ client_yielded: clientCalls.length
832664
832864
  });
832665
- continue;
832865
+ jsonResponse(res, 200, {
832866
+ ...parsed,
832867
+ id: chatId,
832868
+ _agent_loop: {
832869
+ turns: turn,
832870
+ log: turnsLog,
832871
+ done: false,
832872
+ reason: "client_tools_pending",
832873
+ pending_tool_calls: clientCalls.length
832874
+ }
832875
+ });
832876
+ return;
832666
832877
  }
832667
- let tool = null;
832668
- try {
832669
- tool = new meta.ToolClass(process.cwd());
832670
- } catch {
832878
+ messages2.push(message2);
832879
+ let executed = 0;
832880
+ for (const tc of daemonCalls) {
832881
+ const name10 = tc?.function?.name ?? tc?.name ?? "";
832882
+ const argsRaw = tc?.function?.arguments ?? tc?.arguments ?? "{}";
832883
+ let args = {};
832671
832884
  try {
832672
- tool = new meta.ToolClass();
832885
+ args = typeof argsRaw === "string" ? JSON.parse(argsRaw) : argsRaw || {};
832673
832886
  } catch {
832674
- tool = null;
832887
+ args = {};
832888
+ }
832889
+ const denial = canInvoke({ toolName: name10, origin, scope });
832890
+ if (denial) {
832891
+ messages2.push({
832892
+ role: "tool",
832893
+ tool_call_id: tc.id,
832894
+ name: name10,
832895
+ content: JSON.stringify({
832896
+ error: denial.reason,
832897
+ status: denial.status
832898
+ })
832899
+ });
832900
+ continue;
832901
+ }
832902
+ if (activeProfileMeta && !isToolAllowed(activeProfileMeta.profile, name10)) {
832903
+ messages2.push({
832904
+ role: "tool",
832905
+ tool_call_id: tc.id,
832906
+ name: name10,
832907
+ content: JSON.stringify({
832908
+ success: false,
832909
+ error: `Tool '${name10}' is denied by profile '${activeProfileMeta.profile.name}'.`,
832910
+ active_profile: {
832911
+ name: activeProfileMeta.profile.name,
832912
+ source: activeProfileMeta.source,
832913
+ path: activeProfileMeta.path,
832914
+ allowed_tools: allowedToolsForProfile(
832915
+ activeProfileMeta.profile,
832916
+ daemonTools.keys()
832917
+ )
832918
+ }
832919
+ })
832920
+ });
832921
+ continue;
832922
+ }
832923
+ const meta = daemonTools.get(name10);
832924
+ if (!meta) {
832925
+ messages2.push({
832926
+ role: "tool",
832927
+ tool_call_id: tc.id,
832928
+ name: name10,
832929
+ content: JSON.stringify({ error: `Daemon tool '${name10}' not found` })
832930
+ });
832931
+ continue;
832932
+ }
832933
+ let tool = null;
832934
+ try {
832935
+ tool = new meta.ToolClass(process.cwd());
832936
+ } catch {
832937
+ try {
832938
+ tool = new meta.ToolClass();
832939
+ } catch {
832940
+ tool = null;
832941
+ }
832942
+ }
832943
+ if (!tool) {
832944
+ messages2.push({
832945
+ role: "tool",
832946
+ tool_call_id: tc.id,
832947
+ name: name10,
832948
+ content: JSON.stringify({
832949
+ error: `Could not instantiate ${meta.classKey}`
832950
+ })
832951
+ });
832952
+ continue;
832953
+ }
832954
+ if (isClientDisconnected()) return;
832955
+ const remainingToolMs = totalDeadline - Date.now();
832956
+ if (remainingToolMs <= 0) {
832957
+ jsonResponse(res, 504, {
832958
+ error: "agent_loop timed out",
832959
+ turn,
832960
+ elapsed_ms: Date.now() - startMs,
832961
+ timeout_s: perReqTimeoutS ?? null
832962
+ });
832963
+ return;
832964
+ }
832965
+ let toolResult;
832966
+ try {
832967
+ activeTool = tool;
832968
+ const execution = await executeAgentLoopToolBounded(
832969
+ tool,
832970
+ args,
832971
+ Math.min(getAgentLoopToolTimeoutMs(), remainingToolMs),
832972
+ clientDisconnect
832973
+ );
832974
+ if (execution.clientDisconnected || isClientDisconnected()) return;
832975
+ toolResult = execution.result;
832976
+ } catch (e2) {
832977
+ if (isClientDisconnected()) return;
832978
+ toolResult = {
832979
+ success: false,
832980
+ output: "",
832981
+ error: e2 instanceof Error ? e2.message : String(e2),
832982
+ durationMs: 0
832983
+ };
832984
+ } finally {
832985
+ activeTool = null;
832675
832986
  }
832676
- }
832677
- if (!tool) {
832678
832987
  messages2.push({
832679
832988
  role: "tool",
832680
832989
  tool_call_id: tc.id,
832681
832990
  name: name10,
832682
- content: JSON.stringify({
832683
- error: `Could not instantiate ${meta.classKey}`
832684
- })
832991
+ content: JSON.stringify(toolResult)
832685
832992
  });
832686
- continue;
832993
+ executed++;
832687
832994
  }
832688
- let toolResult;
832689
- try {
832690
- toolResult = await tool.execute(args);
832691
- } catch (e2) {
832692
- toolResult = {
832693
- success: false,
832694
- output: "",
832695
- error: e2 instanceof Error ? e2.message : String(e2),
832696
- durationMs: 0
832697
- };
832698
- }
832699
- messages2.push({
832700
- role: "tool",
832701
- tool_call_id: tc.id,
832702
- name: name10,
832703
- content: JSON.stringify(toolResult)
832995
+ turnsLog.push({
832996
+ turn,
832997
+ tool_calls: toolCalls.length,
832998
+ daemon_executed: executed,
832999
+ client_yielded: 0
832704
833000
  });
832705
- executed++;
832706
833001
  }
832707
- turnsLog.push({
832708
- turn,
832709
- tool_calls: toolCalls.length,
832710
- daemon_executed: executed,
832711
- client_yielded: 0
833002
+ jsonResponse(res, 200, {
833003
+ id: chatId,
833004
+ object: "chat.completion",
833005
+ created: Math.floor(Date.now() / 1e3),
833006
+ model,
833007
+ choices: [
833008
+ {
833009
+ index: 0,
833010
+ message: {
833011
+ role: "assistant",
833012
+ content: "[agent_loop reached max_turns without producing a final answer]"
833013
+ },
833014
+ finish_reason: "length"
833015
+ }
833016
+ ],
833017
+ _agent_loop: {
833018
+ turns: maxTurns,
833019
+ log: turnsLog,
833020
+ done: false,
833021
+ reason: "max_turns_exhausted",
833022
+ max_turns: maxTurns
833023
+ }
832712
833024
  });
833025
+ } finally {
833026
+ req3.removeListener("aborted", onRequestAborted);
833027
+ req3.removeListener("close", onRequestClose);
833028
+ req3.removeListener("error", onRequestError);
833029
+ res.removeListener("close", onResponseClose);
833030
+ res.removeListener("error", onResponseError);
832713
833031
  }
832714
- jsonResponse(res, 200, {
832715
- id: chatId,
832716
- object: "chat.completion",
832717
- created: Math.floor(Date.now() / 1e3),
832718
- model,
832719
- choices: [
832720
- {
832721
- index: 0,
832722
- message: {
832723
- role: "assistant",
832724
- content: "[agent_loop reached max_turns without producing a final answer]"
832725
- },
832726
- finish_reason: "length"
832727
- }
832728
- ],
832729
- _agent_loop: {
832730
- turns: maxTurns,
832731
- log: turnsLog,
832732
- done: false,
832733
- reason: "max_turns_exhausted",
832734
- max_turns: maxTurns
832735
- }
832736
- });
832737
833032
  }
832738
833033
  async function handleV1ChatCompletions(req3, res, ollamaUrl) {
832739
833034
  const body = await parseJsonBody(req3);
@@ -841203,7 +841498,7 @@ function setTimerEnabled(name10, enabled2) {
841203
841498
  return false;
841204
841499
  }
841205
841500
  }
841206
- var require4, NEXUS_DIRECTORY_ORIGIN3, NEXUS_SPONSORS_URL3, SERVER_BOOT_IDENTITY, voiceTtsTransactionTail, endpointRegistry, modelRouteMap, endpointUsage, _lastEndpointDiagnostics, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, MODEL_LIST_TIMEOUT_DEFAULT_MS, MODEL_CHECK_TIMEOUT_DEFAULT_MS, MODEL_CHECK_TIMEOUT_MAX_MS, MODEL_CHECK_MAX_TOKENS, metrics, startedAt, FILE_MIME_BY_EXT, realtimeOllamaFallbackCache, runningProcesses, LOCAL_UI_SESSION_COOKIE, LOCAL_UI_SESSION_TOKEN, perKeyUsage, CRON_MARKER2;
841501
+ var require4, NEXUS_DIRECTORY_ORIGIN3, NEXUS_SPONSORS_URL3, SERVER_BOOT_IDENTITY, voiceTtsTransactionTail, endpointRegistry, modelRouteMap, endpointUsage, _lastEndpointDiagnostics, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, AGENT_LOOP_TOTAL_MAX_MS, AGENT_LOOP_TOOL_TIMEOUT_DEFAULT_MS, AGENT_LOOP_TOOL_TIMEOUT_MAX_MS, MODEL_LIST_TIMEOUT_DEFAULT_MS, MODEL_CHECK_TIMEOUT_DEFAULT_MS, MODEL_CHECK_TIMEOUT_MAX_MS, MODEL_CHECK_MAX_TOKENS, cancelledAgentLoopTools, metrics, startedAt, FILE_MIME_BY_EXT, realtimeOllamaFallbackCache, runningProcesses, LOCAL_UI_SESSION_COOKIE, LOCAL_UI_SESSION_TOKEN, perKeyUsage, CRON_MARKER2;
841207
841502
  var init_serve = __esm({
841208
841503
  "packages/cli/src/api/serve.ts"() {
841209
841504
  init_config();
@@ -841259,10 +841554,14 @@ var init_serve = __esm({
841259
841554
  _lastEndpointDiagnostics = [];
841260
841555
  BACKEND_TIMEOUT_DEFAULT_MS = 12e4;
841261
841556
  BACKEND_TIMEOUT_MAX_MS = 36e5;
841557
+ AGENT_LOOP_TOTAL_MAX_MS = 30 * 60 * 1e3;
841558
+ AGENT_LOOP_TOOL_TIMEOUT_DEFAULT_MS = 3e4;
841559
+ AGENT_LOOP_TOOL_TIMEOUT_MAX_MS = 12e4;
841262
841560
  MODEL_LIST_TIMEOUT_DEFAULT_MS = 1500;
841263
841561
  MODEL_CHECK_TIMEOUT_DEFAULT_MS = 1e4;
841264
841562
  MODEL_CHECK_TIMEOUT_MAX_MS = 3e4;
841265
841563
  MODEL_CHECK_MAX_TOKENS = 32;
841564
+ cancelledAgentLoopTools = /* @__PURE__ */ new WeakSet();
841266
841565
  metrics = {
841267
841566
  requests: /* @__PURE__ */ new Map(),
841268
841567
  totalTokensIn: 0,