omnius 1.0.267 → 1.0.268

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
@@ -557292,7 +557292,7 @@ var init_ollama_pool = __esm({
557292
557292
  elasticSpawnCap(gpus) {
557293
557293
  return this.config.maxSpawnedInstances > 0 ? this.config.maxSpawnedInstances : Math.max(0, gpus.length - 1);
557294
557294
  }
557295
- async getGpusForPlacement(maxAgeMs = 3e3) {
557295
+ async getGpusForPlacement(maxAgeMs = 3e4) {
557296
557296
  const now2 = Date.now();
557297
557297
  if (this.gpuCache && now2 - this.gpuCache.takenAtMs <= maxAgeMs) {
557298
557298
  return this.gpuCache.gpus;
@@ -557366,7 +557366,12 @@ var init_ollama_pool = __esm({
557366
557366
  }
557367
557367
  const gpuUuid = gpu?.uuid || null;
557368
557368
  const gpuIndex = gpu?.index ?? null;
557369
- const { proc, ready } = await this.spawner({ port, gpuUuid, gpuIndex, config: this.config });
557369
+ const { proc, ready } = await this.spawner({
557370
+ port,
557371
+ gpuUuid,
557372
+ gpuIndex,
557373
+ config: this.config
557374
+ });
557370
557375
  try {
557371
557376
  await ready;
557372
557377
  } catch (err) {
@@ -562511,6 +562516,8 @@ var init_streaming_executor = __esm({
562511
562516
  insertionOrder = [];
562512
562517
  config;
562513
562518
  executeFn = null;
562519
+ /** Resolver for notification-based wait (delay-1: replaces 1ms spin loop) */
562520
+ _notifyResolve = null;
562514
562521
  constructor(config) {
562515
562522
  this.config = {
562516
562523
  maxConcurrent: config?.maxConcurrent ?? 5,
@@ -562588,6 +562595,18 @@ var init_streaming_executor = __esm({
562588
562595
  }
562589
562596
  return results;
562590
562597
  }
562598
+ /** Signal the notification promise (wake waitAll if sleeping) */
562599
+ _signalChange() {
562600
+ const r2 = this._notifyResolve;
562601
+ this._notifyResolve = null;
562602
+ r2?.();
562603
+ }
562604
+ /** Create a new notification promise for waitAll to await */
562605
+ _waitForChange() {
562606
+ return new Promise((resolve70) => {
562607
+ this._notifyResolve = resolve70;
562608
+ });
562609
+ }
562591
562610
  /**
562592
562611
  * Wait for all queued/executing tools to complete.
562593
562612
  */
@@ -562603,7 +562622,7 @@ var init_streaming_executor = __esm({
562603
562622
  this.processQueue();
562604
562623
  } else {
562605
562624
  this.processQueue();
562606
- await new Promise((r2) => setTimeout(r2, 1));
562625
+ await this._waitForChange();
562607
562626
  }
562608
562627
  }
562609
562628
  }
@@ -562740,6 +562759,7 @@ var init_streaming_executor = __esm({
562740
562759
  break;
562741
562760
  }
562742
562761
  }
562762
+ this._signalChange();
562743
562763
  }
562744
562764
  startExecution(entry) {
562745
562765
  entry.state = "executing";
@@ -563908,7 +563928,11 @@ function captureToolchainVersions() {
563908
563928
  const out = {};
563909
563929
  for (const probe of TOOLCHAIN_PROBES) {
563910
563930
  try {
563911
- const v = execSync47(probe.cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 1500 }).trim();
563931
+ const v = execSync47(probe.cmd, {
563932
+ encoding: "utf8",
563933
+ stdio: ["ignore", "pipe", "ignore"],
563934
+ timeout: 500
563935
+ }).trim();
563912
563936
  out[probe.name] = v.split(/\r?\n/)[0].slice(0, 200);
563913
563937
  } catch {
563914
563938
  out[probe.name] = null;
@@ -563929,7 +563953,10 @@ function freeDiskBytes(path12 = "/tmp") {
563929
563953
  const st = statSync35(path12);
563930
563954
  if (!st.isDirectory())
563931
563955
  return -1;
563932
- const out = execSync47(`df -P -k ${JSON.stringify(path12)} | tail -1`, { encoding: "utf8", timeout: 1500 });
563956
+ const out = execSync47(`df -P -k ${JSON.stringify(path12)} | tail -1`, {
563957
+ encoding: "utf8",
563958
+ timeout: 500
563959
+ });
563933
563960
  const cols = out.trim().split(/\s+/);
563934
563961
  const availKb = parseInt(cols[3] ?? "0", 10);
563935
563962
  if (!Number.isFinite(availKb))
@@ -581407,21 +581434,30 @@ var init_cascadeBackend = __esm({
581407
581434
  } catch (err) {
581408
581435
  this.consecutiveFailures++;
581409
581436
  if (this.isTransientError(err) && this.consecutiveFailures >= this.maxFailures) {
581410
- const nextIdx = this.findNextAvailableEndpoint();
581411
- if (nextIdx !== null && nextIdx !== this.activeIndex) {
581437
+ const candidates = this.endpoints.filter((_ep, i2) => i2 !== this.activeIndex && _ep.modelAvailable !== false);
581438
+ if (candidates.length > 0) {
581412
581439
  const from3 = this.endpoints[this.activeIndex];
581413
- const to = this.endpoints[nextIdx];
581414
581440
  const reason = `${this.consecutiveFailures} consecutive failures: ${err instanceof Error ? err.message : String(err)}`;
581415
- this.activeIndex = nextIdx;
581416
- this.consecutiveFailures = 0;
581417
- this.onSwitch?.(from3, to, reason);
581418
- const newBackend = this.getActiveBackend();
581441
+ const promises = candidates.map((ep) => {
581442
+ const bk = this.backends.get(ep.url);
581443
+ return bk.chatCompletion(request).then((result) => ({ result, from: ep }));
581444
+ });
581419
581445
  try {
581420
- const result = await newBackend.chatCompletion(request);
581446
+ const { result, from: from4 } = await Promise.race(promises);
581447
+ const winnerIdx = this.endpoints.indexOf(from4);
581448
+ if (winnerIdx >= 0) {
581449
+ this.activeIndex = winnerIdx;
581450
+ this.onSwitch?.(from4, from4, reason);
581451
+ }
581452
+ this.consecutiveFailures = 0;
581421
581453
  return result;
581422
- } catch (cascadeErr) {
581423
- this.consecutiveFailures++;
581424
- throw cascadeErr;
581454
+ } catch {
581455
+ this.consecutiveFailures += candidates.length;
581456
+ throw err;
581457
+ } finally {
581458
+ for (const p2 of promises)
581459
+ p2.catch(() => {
581460
+ });
581425
581461
  }
581426
581462
  }
581427
581463
  }
@@ -581636,7 +581672,7 @@ function createSteeringIngress(input) {
581636
581672
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
581637
581673
  };
581638
581674
  }
581639
- async function interpretSteeringIngress(backend, ingress, timeoutMs = 15e3) {
581675
+ async function interpretSteeringIngress(backend, ingress, timeoutMs = 8e3) {
581640
581676
  const first2 = await backend.chatCompletion({
581641
581677
  messages: [
581642
581678
  {
@@ -594350,6 +594386,175 @@ var init_task_complete_box = __esm({
594350
594386
  }
594351
594387
  });
594352
594388
 
594389
+ // packages/cli/src/tui/syntax-highlight.ts
594390
+ var syntax_highlight_exports = {};
594391
+ __export(syntax_highlight_exports, {
594392
+ detectLanguage: () => detectLanguage2,
594393
+ getHighlightStatus: () => getHighlightStatus,
594394
+ highlightBlock: () => highlightBlock,
594395
+ highlightCode: () => highlightCode,
594396
+ isAvailable: () => isAvailable,
594397
+ prewarm: () => prewarm
594398
+ });
594399
+ function highlightingDisabled() {
594400
+ return !isTTY2 || noColorEnv || disableEnv;
594401
+ }
594402
+ async function loadHighlighter() {
594403
+ if (_state.attempted) return _state.fn;
594404
+ _state.attempted = true;
594405
+ if (highlightingDisabled()) {
594406
+ _state.reason = !isTTY2 ? "non-tty" : noColorEnv ? "NO_COLOR set" : "OMNIUS_TUI_HIGHLIGHT=0";
594407
+ return null;
594408
+ }
594409
+ try {
594410
+ const { createRequire: createRequire10 } = await import("node:module");
594411
+ const req3 = createRequire10(import.meta.url);
594412
+ let resolved = null;
594413
+ try {
594414
+ resolved = req3.resolve("cli-highlight");
594415
+ } catch {
594416
+ _state.reason = "cli-highlight not installed";
594417
+ return null;
594418
+ }
594419
+ const mod3 = await import(resolved).catch(() => null);
594420
+ if (!mod3) {
594421
+ _state.reason = "cli-highlight failed to load";
594422
+ return null;
594423
+ }
594424
+ const m2 = mod3;
594425
+ const candidate = m2.highlight ?? m2.default ?? null;
594426
+ if (typeof candidate !== "function") {
594427
+ _state.reason = "cli-highlight export shape unrecognized";
594428
+ return null;
594429
+ }
594430
+ _state.fn = candidate;
594431
+ return candidate;
594432
+ } catch (err) {
594433
+ _state.reason = `import threw: ${err?.message ?? String(err)}`;
594434
+ return null;
594435
+ }
594436
+ }
594437
+ function loadHighlighterSync() {
594438
+ if (highlightingDisabled()) return null;
594439
+ return _state.fn;
594440
+ }
594441
+ async function prewarm() {
594442
+ await loadHighlighter();
594443
+ }
594444
+ function isAvailable() {
594445
+ if (highlightingDisabled()) return false;
594446
+ return _state.attempted && _state.fn !== null;
594447
+ }
594448
+ function getHighlightStatus() {
594449
+ return {
594450
+ available: isAvailable(),
594451
+ attempted: _state.attempted,
594452
+ reason: _state.reason,
594453
+ isTTY: isTTY2,
594454
+ noColor: noColorEnv,
594455
+ disabledByEnv: disableEnv
594456
+ };
594457
+ }
594458
+ function highlightCode(code8, language) {
594459
+ if (!code8) return code8;
594460
+ const fn = loadHighlighterSync();
594461
+ if (!fn) return code8;
594462
+ const lang = (language ?? detectLanguage2(code8) ?? "").trim();
594463
+ try {
594464
+ if (lang) {
594465
+ return fn(code8, { language: lang, ignoreIllegals: true });
594466
+ }
594467
+ return fn(code8, { ignoreIllegals: true });
594468
+ } catch {
594469
+ return code8;
594470
+ }
594471
+ }
594472
+ function detectLanguage2(text2) {
594473
+ if (!text2) return null;
594474
+ const trimmed = text2.trimStart();
594475
+ const shebang = trimmed.match(/^#!\s*\/[^\n]+/);
594476
+ if (shebang) {
594477
+ const sb = shebang[0];
594478
+ if (/python/.test(sb)) return "python";
594479
+ if (/(?:^|[\s/])(?:bash|sh|zsh)\b/.test(sb)) return "bash";
594480
+ if (/node/.test(sb)) return "javascript";
594481
+ if (/ruby/.test(sb)) return "ruby";
594482
+ if (/perl/.test(sb)) return "perl";
594483
+ }
594484
+ if (/^[\s\n]*[{[]/.test(trimmed)) {
594485
+ try {
594486
+ JSON.parse(trimmed);
594487
+ return "json";
594488
+ } catch {
594489
+ }
594490
+ }
594491
+ if (/^[-a-zA-Z_][\w-]*:\s/.test(trimmed) && /\n[-a-zA-Z_][\w-]*:\s/.test(trimmed)) {
594492
+ return "yaml";
594493
+ }
594494
+ if (/^(?:async def |def |class |import |from )/.test(trimmed) && /(?::\s*$|->|self\b)/m.test(trimmed)) {
594495
+ return "python";
594496
+ }
594497
+ if (/^(?:import |export |const |let |var |function |class |interface |type |async )/.test(trimmed)) {
594498
+ if (/(:\s*(?:string|number|boolean|any|unknown|void)\b|\binterface\b|\btype\s+\w+\s*=)/.test(trimmed)) {
594499
+ return "typescript";
594500
+ }
594501
+ return "javascript";
594502
+ }
594503
+ if (/(?:^|\n)\s*(?:fn |use |let mut |impl |struct |enum |trait )/.test(trimmed)) {
594504
+ return "rust";
594505
+ }
594506
+ if (/(?:^package \w+|\nfunc \w+\s*\()/.test(trimmed)) {
594507
+ return "go";
594508
+ }
594509
+ if (/^\s*(?:SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i.test(trimmed)) {
594510
+ return "sql";
594511
+ }
594512
+ if (/^[\s\n]*<(?:!DOCTYPE|html|\?xml|\w+)/i.test(trimmed)) {
594513
+ return "html";
594514
+ }
594515
+ if (/^(?:---|\+\+\+|@@|diff )/.test(trimmed)) {
594516
+ return "diff";
594517
+ }
594518
+ if (/^\s*(?:\$\s|sudo |apt |brew |npm |pnpm |yarn |git |docker |kubectl |curl |wget )/.test(trimmed)) {
594519
+ return "bash";
594520
+ }
594521
+ return null;
594522
+ }
594523
+ function highlightBlock(code8, language) {
594524
+ if (!code8) return [""];
594525
+ const fn = loadHighlighterSync();
594526
+ if (!fn) return code8.split("\n");
594527
+ const lang = (language ?? detectLanguage2(code8) ?? "").trim();
594528
+ try {
594529
+ const out = lang ? fn(code8, { language: lang, ignoreIllegals: true }) : fn(code8, { ignoreIllegals: true });
594530
+ const lines = out.split("\n");
594531
+ const inputLines = code8.split("\n");
594532
+ if (lines.length === inputLines.length) return lines;
594533
+ if (lines.length < inputLines.length) {
594534
+ while (lines.length < inputLines.length) lines.push("");
594535
+ } else {
594536
+ lines.length = inputLines.length;
594537
+ }
594538
+ return lines;
594539
+ } catch {
594540
+ return code8.split("\n");
594541
+ }
594542
+ }
594543
+ var isTTY2, noColorEnv, disableEnv, _state;
594544
+ var init_syntax_highlight = __esm({
594545
+ "packages/cli/src/tui/syntax-highlight.ts"() {
594546
+ "use strict";
594547
+ isTTY2 = process.stdout?.isTTY ?? false;
594548
+ noColorEnv = process.env["NO_COLOR"] !== void 0 && process.env["NO_COLOR"] !== "";
594549
+ disableEnv = process.env["OMNIUS_TUI_HIGHLIGHT"] === "0";
594550
+ _state = {
594551
+ attempted: false,
594552
+ fn: null,
594553
+ reason: ""
594554
+ };
594555
+ }
594556
+ });
594557
+
594353
594558
  // packages/cli/src/tui/model-picker.ts
594354
594559
  import { totalmem as totalmem4 } from "node:os";
594355
594560
  function isImageGenModel(name10, family) {
@@ -596058,10 +596263,29 @@ function diffBodyLines(output, verbose) {
596058
596263
  for (const line of lines.slice(0, maxLines)) {
596059
596264
  const m2 = line.match(DIFF_LINE_RE);
596060
596265
  if (m2) {
596061
- const colored = m2[1] === "+" ? c3.green(line) : c3.red(line);
596266
+ const marker = m2[1];
596267
+ const codeStart = m2.index + m2[0].length;
596268
+ const prefix = line.slice(0, codeStart);
596269
+ const code8 = line.slice(codeStart);
596270
+ let hlCode = code8;
596271
+ if (isAvailable() && code8.trim()) {
596272
+ const hl = highlightCode(code8);
596273
+ if (hl !== code8) hlCode = hl;
596274
+ }
596275
+ const colorSeq = marker === "+" ? "\x1B[32m" : "\x1B[31m";
596276
+ const resetRe = /\x1B\[0m/g;
596277
+ const adjusted = hlCode.replace(resetRe, `\x1B[0m${colorSeq}`);
596278
+ const colored = `${colorSeq}${prefix}${adjusted}\x1B[0m`;
596062
596279
  body.push({ text: colored, mode: "truncate", kind: "plain" });
596063
596280
  } else {
596064
- body.push({ text: line, mode: "wrap", kind: "dim" });
596281
+ let formatted = line;
596282
+ if (isAvailable() && line.trim()) {
596283
+ const hl = highlightCode(line);
596284
+ formatted = hl !== line ? hl : c3.dim(line);
596285
+ } else {
596286
+ formatted = c3.dim(line);
596287
+ }
596288
+ body.push({ text: formatted, mode: "wrap", kind: "plain" });
596065
596289
  }
596066
596290
  }
596067
596291
  if (lines.length > maxLines) {
@@ -596081,11 +596305,16 @@ function codePreviewLines(output, maxLines) {
596081
596305
  const shown = lines.slice(start2, start2 + maxLines);
596082
596306
  if (shown.length === 0)
596083
596307
  return [{ text: "(empty file)", mode: "wrap", kind: "dim" }];
596084
- const body = shown.map((line) => ({
596085
- text: line,
596308
+ let hlLines = null;
596309
+ if (isAvailable()) {
596310
+ const codeBlock = shown.join("\n");
596311
+ const hl = highlightBlock(codeBlock);
596312
+ if (hl.length === shown.length) hlLines = hl;
596313
+ }
596314
+ const body = shown.map((line, i2) => ({
596315
+ text: hlLines ? hlLines[i2] ?? line : line,
596086
596316
  mode: "truncate",
596087
596317
  kind: "plain"
596088
- // show content in default terminal color, not dim
596089
596318
  }));
596090
596319
  const remaining = lines.length - start2 - shown.length;
596091
596320
  if (remaining > 0) {
@@ -596580,6 +596809,7 @@ var init_render = __esm({
596580
596809
  init_config();
596581
596810
  init_text_selection();
596582
596811
  init_task_complete_box();
596812
+ init_syntax_highlight();
596583
596813
  init_model_picker();
596584
596814
  init_secret_redactor();
596585
596815
  c3 = {
@@ -610028,10 +610258,10 @@ ${CONTENT_BG_SEQ}`);
610028
610258
  // packages/cli/src/tui/tui-select.ts
610029
610259
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
610030
610260
  function ansi3(code8, text2) {
610031
- return isTTY2 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
610261
+ return isTTY3 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
610032
610262
  }
610033
610263
  function fg2563(code8, text2) {
610034
- return isTTY2 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
610264
+ return isTTY3 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
610035
610265
  }
610036
610266
  function stripAnsi3(s2) {
610037
610267
  return s2.replace(/\x1B\[[0-9;]*m/g, "");
@@ -610684,14 +610914,14 @@ ${tuiBgSeq()}`);
610684
610914
  }
610685
610915
  });
610686
610916
  }
610687
- var isTTY2, MENU_ACTIVE_GREEN_256, selectColors, nonInteractiveSelectSurface;
610917
+ var isTTY3, MENU_ACTIVE_GREEN_256, selectColors, nonInteractiveSelectSurface;
610688
610918
  var init_tui_select = __esm({
610689
610919
  "packages/cli/src/tui/tui-select.ts"() {
610690
610920
  "use strict";
610691
610921
  init_overlay_lock();
610692
610922
  init_theme();
610693
610923
  init_layout2();
610694
- isTTY2 = process.stdout.isTTY ?? false;
610924
+ isTTY3 = process.stdout.isTTY ?? false;
610695
610925
  MENU_ACTIVE_GREEN_256 = 154;
610696
610926
  selectColors = {
610697
610927
  blue: (t2) => fg2563(39, t2),
@@ -616167,7 +616397,7 @@ var init_format = __esm({
616167
616397
  import { existsSync as existsSync116 } from "node:fs";
616168
616398
  import { extname as extname17, resolve as resolve55 } from "node:path";
616169
616399
  function ansi4(code8, text2) {
616170
- return isTTY3 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
616400
+ return isTTY4 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
616171
616401
  }
616172
616402
  function stripAnsi4(s2) {
616173
616403
  return s2.replace(/\x1B\[[0-9;]*m/g, "");
@@ -616338,13 +616568,13 @@ function showDropPanel(opts) {
616338
616568
  render2();
616339
616569
  });
616340
616570
  }
616341
- var isTTY3, dc;
616571
+ var isTTY4, dc;
616342
616572
  var init_drop_panel = __esm({
616343
616573
  "packages/cli/src/tui/drop-panel.ts"() {
616344
616574
  "use strict";
616345
616575
  init_overlay_lock();
616346
616576
  init_layout2();
616347
- isTTY3 = process.stdout.isTTY ?? false;
616577
+ isTTY4 = process.stdout.isTTY ?? false;
616348
616578
  dc = {
616349
616579
  bold: (t2) => ansi4("1", t2),
616350
616580
  dim: (t2) => ansi4("38;5;250", t2),
@@ -618643,17 +618873,17 @@ import { tmpdir as tmpdir20 } from "node:os";
618643
618873
  import { join as join131 } from "node:path";
618644
618874
  import { execSync as execSync54 } from "node:child_process";
618645
618875
  function isNeovimActive() {
618646
- return _state !== null && !_state.cleanedUp;
618876
+ return _state2 !== null && !_state2.cleanedUp;
618647
618877
  }
618648
618878
  function isNeovimFocused() {
618649
- return _state?.focused ?? false;
618879
+ return _state2?.focused ?? false;
618650
618880
  }
618651
618881
  function refocusNeovim() {
618652
- if (!_state || _state.cleanedUp || _state.focused) return;
618653
- toggleFocus(_state);
618882
+ if (!_state2 || _state2.cleanedUp || _state2.focused) return;
618883
+ toggleFocus(_state2);
618654
618884
  }
618655
618885
  async function startNeovimMode(opts) {
618656
- if (_state && !_state.cleanedUp) {
618886
+ if (_state2 && !_state2.cleanedUp) {
618657
618887
  return "Neovim mode is already active. Use /neovim to exit first.";
618658
618888
  }
618659
618889
  let nvimPath;
@@ -618694,7 +618924,7 @@ async function startNeovimMode(opts) {
618694
618924
  const ptyCols = opts.cols;
618695
618925
  const topOffset = opts.topOffset ?? 0;
618696
618926
  const ptyRows = Math.max(5, opts.contentRows);
618697
- if (isTTY4) {
618927
+ if (isTTY5) {
618698
618928
  const L = layout();
618699
618929
  const bottomBound = L.contentBottom;
618700
618930
  process.stdout.write(
@@ -618743,7 +618973,7 @@ async function startNeovimMode(opts) {
618743
618973
  installedFilteredListeners: [],
618744
618974
  cleanedUp: false
618745
618975
  };
618746
- _state = state;
618976
+ _state2 = state;
618747
618977
  const toolbarBtns = [];
618748
618978
  {
618749
618979
  const btns = [
@@ -618763,7 +618993,7 @@ async function startNeovimMode(opts) {
618763
618993
  }
618764
618994
  }
618765
618995
  function renderToolbar() {
618766
- if (!isTTY4) return;
618996
+ if (!isTTY5) return;
618767
618997
  const L = layout();
618768
618998
  const hdrRow = L.headerContent;
618769
618999
  const fg2 = 252;
@@ -618824,7 +619054,7 @@ async function startNeovimMode(opts) {
618824
619054
  stdin.setRawMode(true);
618825
619055
  }
618826
619056
  stdin.resume();
618827
- if (isTTY4) {
619057
+ if (isTTY5) {
618828
619058
  process.stdout.write("\x1B[?1002h\x1B[?1006h");
618829
619059
  }
618830
619060
  state.stdinHandler = (data) => {
@@ -618891,12 +619121,12 @@ async function startNeovimMode(opts) {
618891
619121
  return null;
618892
619122
  }
618893
619123
  function stopNeovimMode() {
618894
- if (!_state || _state.cleanedUp) return Promise.resolve();
619124
+ if (!_state2 || _state2.cleanedUp) return Promise.resolve();
618895
619125
  try {
618896
- _state.pty?.write("\x1B:qa!\r");
619126
+ _state2.pty?.write("\x1B:qa!\r");
618897
619127
  } catch {
618898
619128
  }
618899
- const s2 = _state;
619129
+ const s2 = _state2;
618900
619130
  return new Promise((resolve70) => {
618901
619131
  setTimeout(() => {
618902
619132
  if (s2 && !s2.cleanedUp) {
@@ -618907,18 +619137,18 @@ function stopNeovimMode() {
618907
619137
  });
618908
619138
  }
618909
619139
  function writeToNeovimOutput(text2) {
618910
- if (!_state || _state.cleanedUp || !_state.nvim || !_state.outputChanId) return;
619140
+ if (!_state2 || _state2.cleanedUp || !_state2.nvim || !_state2.outputChanId) return;
618911
619141
  const normalized = text2.replace(/(?<!\r)\n/g, "\r\n");
618912
- _state.nvim.request("nvim_chan_send", [_state.outputChanId, normalized]).catch(() => {
619142
+ _state2.nvim.request("nvim_chan_send", [_state2.outputChanId, normalized]).catch(() => {
618913
619143
  });
618914
619144
  }
618915
619145
  async function notifyNeovimFileChange(filePath) {
618916
- if (!_state || _state.cleanedUp || !_state.nvim) return;
619146
+ if (!_state2 || _state2.cleanedUp || !_state2.nvim) return;
618917
619147
  try {
618918
- await _state.nvim.command("checktime");
619148
+ await _state2.nvim.command("checktime");
618919
619149
  if (filePath) {
618920
619150
  const escaped = filePath.replace(/'/g, "''");
618921
- await _state.nvim.command(
619151
+ await _state2.nvim.command(
618922
619152
  `if bufexists('${escaped}') | execute 'buffer ' . bufnr('${escaped}') | endif`
618923
619153
  );
618924
619154
  }
@@ -618926,10 +619156,10 @@ async function notifyNeovimFileChange(filePath) {
618926
619156
  }
618927
619157
  }
618928
619158
  function resizeNeovim(cols, contentRows) {
618929
- if (!_state || _state.cleanedUp || !_state.pty) return;
619159
+ if (!_state2 || _state2.cleanedUp || !_state2.pty) return;
618930
619160
  const rows = Math.max(5, contentRows);
618931
619161
  try {
618932
- _state.pty.resize(cols, rows);
619162
+ _state2.pty.resize(cols, rows);
618933
619163
  } catch {
618934
619164
  }
618935
619165
  }
@@ -619104,7 +619334,7 @@ function doCleanup(state) {
619104
619334
  } catch {
619105
619335
  }
619106
619336
  }
619107
- _state = null;
619337
+ _state2 = null;
619108
619338
  process.stdout.write(
619109
619339
  `\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?1004l\x1B[?2004l\x1B[1;${termRows()}r`
619110
619340
  // reset scroll region to full terminal
@@ -619123,16 +619353,16 @@ function doCleanup(state) {
619123
619353
  }
619124
619354
  state.opts.onExit?.();
619125
619355
  }
619126
- var isTTY4, PTY_MODE_ENABLE_RE, STDIN_MOUSE_FOCUS_RE, _state;
619356
+ var isTTY5, PTY_MODE_ENABLE_RE, STDIN_MOUSE_FOCUS_RE, _state2;
619127
619357
  var init_neovim_mode = __esm({
619128
619358
  "packages/cli/src/tui/neovim-mode.ts"() {
619129
619359
  "use strict";
619130
619360
  init_setup();
619131
619361
  init_layout2();
619132
- isTTY4 = process.stdout.isTTY ?? false;
619362
+ isTTY5 = process.stdout.isTTY ?? false;
619133
619363
  PTY_MODE_ENABLE_RE = /\x1B\[\?(?:1004|2004)h/g;
619134
619364
  STDIN_MOUSE_FOCUS_RE = /\x1B\[<[\d;]+[Mm]|\x1B\[M[\s\S]{3}|\x1B\[[IO]|\x1BO[ABCD]/g;
619135
- _state = null;
619365
+ _state2 = null;
619136
619366
  }
619137
619367
  });
619138
619368
 
@@ -644066,7 +644296,7 @@ function setCarouselWriter(writer) {
644066
644296
  chromeWrite2 = writer;
644067
644297
  }
644068
644298
  function fg(code8, text2) {
644069
- return isTTY5 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
644299
+ return isTTY6 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
644070
644300
  }
644071
644301
  function displayWidth(str) {
644072
644302
  let w = 0;
@@ -644104,12 +644334,12 @@ function createRow(phraseIndices, speed, direction, bank2) {
644104
644334
  const phrases = phraseIndices.map((i2) => bank2[i2 % bank2.length]);
644105
644335
  return { phrases, offset: 0, speed, direction, renderedPlain: "" };
644106
644336
  }
644107
- var isTTY5, chromeWrite2, PHRASES, Carousel;
644337
+ var isTTY6, chromeWrite2, PHRASES, Carousel;
644108
644338
  var init_carousel = __esm({
644109
644339
  "packages/cli/src/tui/carousel.ts"() {
644110
644340
  "use strict";
644111
644341
  init_layout2();
644112
- isTTY5 = process.stdout.isTTY ?? false;
644342
+ isTTY6 = process.stdout.isTTY ?? false;
644113
644343
  chromeWrite2 = ((data) => {
644114
644344
  process.stdout.write(data);
644115
644345
  });
@@ -644221,7 +644451,7 @@ var init_carousel = __esm({
644221
644451
  * Sets scroll region to row 5+ for all content/readline.
644222
644452
  */
644223
644453
  start() {
644224
- if (!isTTY5) return 0;
644454
+ if (!isTTY6) return 0;
644225
644455
  this.started = true;
644226
644456
  setHeaderHeight(this.reservedRows);
644227
644457
  const L = layout();
@@ -644253,7 +644483,7 @@ var init_carousel = __esm({
644253
644483
  * Row 4 is left blank as a separator.
644254
644484
  */
644255
644485
  renderFrame() {
644256
- if (!isTTY5) return;
644486
+ if (!isTTY6) return;
644257
644487
  const L = layout();
644258
644488
  let buf = "\x1B7";
644259
644489
  buf += "\x1B[?7l";
@@ -644330,7 +644560,7 @@ var init_carousel = __esm({
644330
644560
  process.stdout.removeListener("resize", this.resizeHandler);
644331
644561
  this.resizeHandler = null;
644332
644562
  }
644333
- if (!isTTY5 || !this.started) return;
644563
+ if (!isTTY6 || !this.started) return;
644334
644564
  const L = layout();
644335
644565
  let buf = "\x1B7";
644336
644566
  for (let i2 = 0; i2 < this.reservedRows; i2++) {
@@ -644566,13 +644796,13 @@ function createAnimatedBanner(id, name10, frameBuilders, frameDurationMs, author
644566
644796
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
644567
644797
  };
644568
644798
  }
644569
- var isTTY6, chromeWrite3, MNEMONIC_ADJECTIVES, MNEMONIC_NOUNS, BannerRenderer;
644799
+ var isTTY7, chromeWrite3, MNEMONIC_ADJECTIVES, MNEMONIC_NOUNS, BannerRenderer;
644570
644800
  var init_banner = __esm({
644571
644801
  "packages/cli/src/tui/banner.ts"() {
644572
644802
  "use strict";
644573
644803
  init_theme();
644574
644804
  init_layout2();
644575
- isTTY6 = process.stdout.isTTY ?? false;
644805
+ isTTY7 = process.stdout.isTTY ?? false;
644576
644806
  chromeWrite3 = ((data) => {
644577
644807
  process.stdout.write(data);
644578
644808
  });
@@ -644734,7 +644964,7 @@ var init_banner = __esm({
644734
644964
  * Returns the number of rows reserved (3 banner + 1 separator = 4).
644735
644965
  */
644736
644966
  start() {
644737
- if (!isTTY6 || !this.currentDesign) return 0;
644967
+ if (!isTTY7 || !this.currentDesign) return 0;
644738
644968
  this.renderCurrentFrame();
644739
644969
  this._resizeHandler = () => {
644740
644970
  setTermSize(process.stdout.rows ?? 24, process.stdout.columns ?? 80);
@@ -644775,7 +645005,7 @@ var init_banner = __esm({
644775
645005
  }
644776
645006
  /** Render the current frame into the top 3 rows (public for refresh callbacks) */
644777
645007
  renderCurrentFrame() {
644778
- if (!isTTY6 || !this.currentDesign) return;
645008
+ if (!isTTY7 || !this.currentDesign) return;
644779
645009
  const frame = this.currentDesign.frames[this.currentFrame];
644780
645010
  if (!frame) return;
644781
645011
  this.width = termCols();
@@ -645179,175 +645409,6 @@ var init_carousel_descriptors = __esm({
645179
645409
  }
645180
645410
  });
645181
645411
 
645182
- // packages/cli/src/tui/syntax-highlight.ts
645183
- var syntax_highlight_exports = {};
645184
- __export(syntax_highlight_exports, {
645185
- detectLanguage: () => detectLanguage2,
645186
- getHighlightStatus: () => getHighlightStatus,
645187
- highlightBlock: () => highlightBlock,
645188
- highlightCode: () => highlightCode,
645189
- isAvailable: () => isAvailable,
645190
- prewarm: () => prewarm
645191
- });
645192
- function highlightingDisabled() {
645193
- return !isTTY7 || noColorEnv || disableEnv;
645194
- }
645195
- async function loadHighlighter() {
645196
- if (_state2.attempted) return _state2.fn;
645197
- _state2.attempted = true;
645198
- if (highlightingDisabled()) {
645199
- _state2.reason = !isTTY7 ? "non-tty" : noColorEnv ? "NO_COLOR set" : "OMNIUS_TUI_HIGHLIGHT=0";
645200
- return null;
645201
- }
645202
- try {
645203
- const { createRequire: createRequire10 } = await import("node:module");
645204
- const req3 = createRequire10(import.meta.url);
645205
- let resolved = null;
645206
- try {
645207
- resolved = req3.resolve("cli-highlight");
645208
- } catch {
645209
- _state2.reason = "cli-highlight not installed";
645210
- return null;
645211
- }
645212
- const mod3 = await import(resolved).catch(() => null);
645213
- if (!mod3) {
645214
- _state2.reason = "cli-highlight failed to load";
645215
- return null;
645216
- }
645217
- const m2 = mod3;
645218
- const candidate = m2.highlight ?? m2.default ?? null;
645219
- if (typeof candidate !== "function") {
645220
- _state2.reason = "cli-highlight export shape unrecognized";
645221
- return null;
645222
- }
645223
- _state2.fn = candidate;
645224
- return candidate;
645225
- } catch (err) {
645226
- _state2.reason = `import threw: ${err?.message ?? String(err)}`;
645227
- return null;
645228
- }
645229
- }
645230
- function loadHighlighterSync() {
645231
- if (highlightingDisabled()) return null;
645232
- return _state2.fn;
645233
- }
645234
- async function prewarm() {
645235
- await loadHighlighter();
645236
- }
645237
- function isAvailable() {
645238
- if (highlightingDisabled()) return false;
645239
- return _state2.attempted && _state2.fn !== null;
645240
- }
645241
- function getHighlightStatus() {
645242
- return {
645243
- available: isAvailable(),
645244
- attempted: _state2.attempted,
645245
- reason: _state2.reason,
645246
- isTTY: isTTY7,
645247
- noColor: noColorEnv,
645248
- disabledByEnv: disableEnv
645249
- };
645250
- }
645251
- function highlightCode(code8, language) {
645252
- if (!code8) return code8;
645253
- const fn = loadHighlighterSync();
645254
- if (!fn) return code8;
645255
- const lang = (language ?? detectLanguage2(code8) ?? "").trim();
645256
- try {
645257
- if (lang) {
645258
- return fn(code8, { language: lang, ignoreIllegals: true });
645259
- }
645260
- return fn(code8, { ignoreIllegals: true });
645261
- } catch {
645262
- return code8;
645263
- }
645264
- }
645265
- function detectLanguage2(text2) {
645266
- if (!text2) return null;
645267
- const trimmed = text2.trimStart();
645268
- const shebang = trimmed.match(/^#!\s*\/[^\n]+/);
645269
- if (shebang) {
645270
- const sb = shebang[0];
645271
- if (/python/.test(sb)) return "python";
645272
- if (/(?:^|[\s/])(?:bash|sh|zsh)\b/.test(sb)) return "bash";
645273
- if (/node/.test(sb)) return "javascript";
645274
- if (/ruby/.test(sb)) return "ruby";
645275
- if (/perl/.test(sb)) return "perl";
645276
- }
645277
- if (/^[\s\n]*[{[]/.test(trimmed)) {
645278
- try {
645279
- JSON.parse(trimmed);
645280
- return "json";
645281
- } catch {
645282
- }
645283
- }
645284
- if (/^[-a-zA-Z_][\w-]*:\s/.test(trimmed) && /\n[-a-zA-Z_][\w-]*:\s/.test(trimmed)) {
645285
- return "yaml";
645286
- }
645287
- if (/^(?:async def |def |class |import |from )/.test(trimmed) && /(?::\s*$|->|self\b)/m.test(trimmed)) {
645288
- return "python";
645289
- }
645290
- if (/^(?:import |export |const |let |var |function |class |interface |type |async )/.test(trimmed)) {
645291
- if (/(:\s*(?:string|number|boolean|any|unknown|void)\b|\binterface\b|\btype\s+\w+\s*=)/.test(trimmed)) {
645292
- return "typescript";
645293
- }
645294
- return "javascript";
645295
- }
645296
- if (/(?:^|\n)\s*(?:fn |use |let mut |impl |struct |enum |trait )/.test(trimmed)) {
645297
- return "rust";
645298
- }
645299
- if (/(?:^package \w+|\nfunc \w+\s*\()/.test(trimmed)) {
645300
- return "go";
645301
- }
645302
- if (/^\s*(?:SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i.test(trimmed)) {
645303
- return "sql";
645304
- }
645305
- if (/^[\s\n]*<(?:!DOCTYPE|html|\?xml|\w+)/i.test(trimmed)) {
645306
- return "html";
645307
- }
645308
- if (/^(?:---|\+\+\+|@@|diff )/.test(trimmed)) {
645309
- return "diff";
645310
- }
645311
- if (/^\s*(?:\$\s|sudo |apt |brew |npm |pnpm |yarn |git |docker |kubectl |curl |wget )/.test(trimmed)) {
645312
- return "bash";
645313
- }
645314
- return null;
645315
- }
645316
- function highlightBlock(code8, language) {
645317
- if (!code8) return [""];
645318
- const fn = loadHighlighterSync();
645319
- if (!fn) return code8.split("\n");
645320
- const lang = (language ?? detectLanguage2(code8) ?? "").trim();
645321
- try {
645322
- const out = lang ? fn(code8, { language: lang, ignoreIllegals: true }) : fn(code8, { ignoreIllegals: true });
645323
- const lines = out.split("\n");
645324
- const inputLines = code8.split("\n");
645325
- if (lines.length === inputLines.length) return lines;
645326
- if (lines.length < inputLines.length) {
645327
- while (lines.length < inputLines.length) lines.push("");
645328
- } else {
645329
- lines.length = inputLines.length;
645330
- }
645331
- return lines;
645332
- } catch {
645333
- return code8.split("\n");
645334
- }
645335
- }
645336
- var isTTY7, noColorEnv, disableEnv, _state2;
645337
- var init_syntax_highlight = __esm({
645338
- "packages/cli/src/tui/syntax-highlight.ts"() {
645339
- "use strict";
645340
- isTTY7 = process.stdout?.isTTY ?? false;
645341
- noColorEnv = process.env["NO_COLOR"] !== void 0 && process.env["NO_COLOR"] !== "";
645342
- disableEnv = process.env["OMNIUS_TUI_HIGHLIGHT"] === "0";
645343
- _state2 = {
645344
- attempted: false,
645345
- fn: null,
645346
- reason: ""
645347
- };
645348
- }
645349
- });
645350
-
645351
645412
  // packages/cli/src/tui/stream-renderer.ts
645352
645413
  function fg2564(code8, text2) {
645353
645414
  return isTTY8 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
@@ -704325,28 +704386,32 @@ ${entry.fullContent}`
704325
704386
  }
704326
704387
  if (lm.intervention) {
704327
704388
  contentWrite(() => {
704328
- const lines = [`⚠ ${lm.intervention}`];
704329
- if (lm.details && showAdversary) {
704330
- const det = String(lm.details);
704331
- lines.push(...det.split("\n").filter(Boolean));
704332
- }
704333
- renderBoxedBlock({
704334
- title: "Adversary",
704335
- lines,
704336
- kind: "plain"
704337
- });
704389
+ renderWarning(`Adversary: ${lm.intervention}`);
704338
704390
  });
704339
704391
  } else if (lm.details && showAdversary) {
704340
704392
  contentWrite(() => {
704341
- renderBoxedBlock({
704342
- title: "Adversary",
704343
- lines: String(lm.details).split("\n").filter(Boolean),
704344
- kind: "dim"
704345
- });
704393
+ renderInfo(
704394
+ `Adversary details: ${String(lm.details).split("\n").filter(Boolean).join(" | ")}`
704395
+ );
704346
704396
  });
704347
704397
  }
704348
704398
  }
704349
704399
  break;
704400
+ case "adversary_reaction":
704401
+ if (event.adversary) {
704402
+ const adv = event.adversary;
704403
+ const conf = adv.confidence != null ? ` (${Math.round(adv.confidence * 100)}%)` : "";
704404
+ const text2 = adv.shortText + conf;
704405
+ contentWrite(() => {
704406
+ renderWarning(`Adversary ${adv.class}: ${text2}`);
704407
+ });
704408
+ if (adv.details) {
704409
+ adversaryBuffer.push(adv.details);
704410
+ if (adversaryBuffer.length > 50)
704411
+ adversaryBuffer.splice(0, adversaryBuffer.length - 50);
704412
+ }
704413
+ }
704414
+ break;
704350
704415
  }
704351
704416
  });
704352
704417
  try {
@@ -0,0 +1,230 @@
1
+ # Unnecessary Causes of Delays Between Agent Actions
2
+
3
+ Analysis of `packages/orchestrator/src/` (95 files) — identified delay sources ranked by impact.
4
+
5
+ ---
6
+
7
+ ## HIGH IMPACT
8
+
9
+ ### 1. `streaming-executor.ts:171-192` — `waitAll()` busy-poll loop
10
+
11
+ ```typescript
12
+ async waitAll(): Promise<void> {
13
+ while (true) {
14
+ const pending = Array.from(this.tools.values()).filter(
15
+ e => e.state === "queued" || e.state === "executing"
16
+ );
17
+ if (pending.length === 0) break;
18
+ const executing = pending.filter(e => e.promise);
19
+ if (executing.length > 0) {
20
+ await Promise.allSettled(executing.map(e => e.promise!));
21
+ this.processQueue();
22
+ } else {
23
+ this.processQueue();
24
+ await new Promise(r => setTimeout(r, 1)); // ← 1ms spin loop
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ **Problem:** When tools are queued but none have started (no `promise`), the loop spins with 1ms `setTimeout` between `processQueue()` calls. Each iteration costs at least 1ms of wall-clock delay. With many queued-but-blocked tools, this adds up.
31
+
32
+ **Fix:** Replace with Promise-based notification (event emitter or `AbortController`-based wait) so the loop yields until a tool completes or a new tool is enqueued.
33
+
34
+ ---
35
+
36
+ ### 2. `ollama-pool.ts:850-869` — Instance readiness probe loop
37
+
38
+ ```typescript
39
+ await new Promise((r) => setTimeout(r, 500)); // ← 500ms between probes
40
+ ```
41
+
42
+ **Problem:** When spawning a new Ollama instance, the code polls `/api/version` every **500ms** with a 2-second abort timeout. This adds **500-2000ms** of delay per new model instance. If the pool is empty and a model isn't loaded, every first request pays this cost.
43
+
44
+ **Fix:** Use exponential backoff (100ms → 200ms → 400ms) or a readiness event emitter instead of fixed polling.
45
+
46
+ ---
47
+
48
+ ### 3. `cascadeBackend.ts:105-156` — Sequential fallback chain
49
+
50
+ ```typescript
51
+ const result = await backend.chatCompletion(request);
52
+ // On failure → try newBackend.chatCompletion(request);
53
+ // On failure → try primaryBackend.chatCompletion({ timeoutMs: 10_000 });
54
+ ```
55
+
56
+ **Problem:** The cascade backend tries multiple backends in sequence. Each failure triggers a retry on the next backend. If the first backend is slow to fail (not crash), the full timeout (10s+) is paid before the fallback activates.
57
+
58
+ **Fix:** Start all backends simultaneously with `Promise.race()` and cancel losers on first success.
59
+
60
+ ---
61
+
62
+ ## MEDIUM IMPACT
63
+
64
+ ### 4. `ollama-pool.ts:1190` — Unbounded slot waiter queue
65
+
66
+ ```typescript
67
+ await new Promise<void>((resolve) => this.slotWaiters.push(resolve));
68
+ ```
69
+
70
+ **Problem:** When all GPU slots are occupied, new requests queue as promises in `slotWaiters`. They only resolve when a slot frees up — but there's no timeout or progress feedback. Under heavy load, this can stall indefinitely.
71
+
72
+ **Fix:** Add a configurable timeout (e.g., 30s) and reject with a clear "no GPU available" error.
73
+
74
+ ---
75
+
76
+ ### 5. `ollama-pool.ts:1336` — GPU detection on every acquire
77
+
78
+ ```typescript
79
+ const rawGpus = await this.gpuDetector();
80
+ ```
81
+
82
+ **Problem:** GPU detection runs on every placement decision. If `gpuDetector()` calls `nvidia-smi` or similar system commands, this adds **10-100ms** per request.
83
+
84
+ **Fix:** Cache GPU detection results with a TTL (e.g., 30s). GPU topology rarely changes at runtime.
85
+
86
+ ---
87
+
88
+ ### 6. `tool-batching.ts:247-253` — Forced serial execution of non-concurrent tools
89
+
90
+ ```typescript
91
+ for (const call of batch.calls) {
92
+ results.push(await executeFn(call));
93
+ }
94
+ ```
95
+
96
+ **Problem:** Write/shell tools are forced to run serially. If the agent produces 3+ write tools in one turn, they queue sequentially. No parallelism for independent writes.
97
+
98
+ **Fix:** Add a write-conflict analyzer (e.g., file-level locking) to allow parallel writes to different files.
99
+
100
+ ---
101
+
102
+ ### 7. `steeringIntake.ts:97` — 15s steering timeout
103
+
104
+ ```typescript
105
+ timeoutMs = 15_000,
106
+ ```
107
+
108
+ **Problem:** Steering intake has a 15-second timeout. If the model is slow or the prompt is large, this adds a full 15s delay before the steering response arrives.
109
+
110
+ **Fix:** Reduce to 5-8s for steering (which is advisory, not critical) or make it non-blocking with a best-effort result.
111
+
112
+ ---
113
+
114
+ ### 8. `verifierRunner.ts:161` — 60s test timeout
115
+
116
+ ```typescript
117
+ timeout: 60_000,
118
+ ```
119
+
120
+ **Problem:** Test execution has a 60-second timeout. If tests hang or are slow, this blocks the entire agent loop.
121
+
122
+ **Fix:** Add a per-test timeout and a total timeout with early termination on repeated failures.
123
+
124
+ ---
125
+
126
+ ## LOW-MEDIUM IMPACT
127
+
128
+ ### 9. `ollama-pool.ts:1236,1257` — VRAM estimation per model
129
+
130
+ ```typescript
131
+ const vramNeededMB = await this.estimateModelVramMB(model);
132
+ ```
133
+
134
+ **Problem:** VRAM estimation runs before every spawn/placement. If it involves model metadata lookups or API calls, this adds latency.
135
+
136
+ **Fix:** Cache VRAM estimates keyed by model name with a TTL.
137
+
138
+ ---
139
+
140
+ ### 10. `streaming-executor.ts:21-26` — `stableValueKey` deep serialization
141
+
142
+ ```typescript
143
+ function stableValueKey(value: unknown): string {
144
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
145
+ if (Array.isArray(value)) return `[${value.map(stableValueKey).join(",")}]`;
146
+ const record = value as Record<string, unknown>;
147
+ return `{${Object.keys(record).sort().map((key) => ...).join(",")}}`;
148
+ }
149
+ ```
150
+
151
+ **Problem:** Deep serialization of tool arguments for deduplication. For large args (e.g., file contents), this adds O(n) serialization cost per tool call.
152
+
153
+ **Fix:** Add a size cap (e.g., 10KB) — if the value exceeds it, use a hash instead of deep serialization.
154
+
155
+ ---
156
+
157
+ ### 11. `streaming-executor.ts:263-291` — Duplicate detection overhead
158
+
159
+ ```typescript
160
+ private findPriorEquivalent(entry: StreamingToolEntry): StreamingToolEntry | null
161
+ private cloneDuplicateResult(entry: StreamingToolEntry): boolean
162
+ private mirrorPriorEquivalent(entry: StreamingToolEntry): boolean
163
+ ```
164
+
165
+ **Problem:** Every tool call is checked against all prior calls for equivalence. This is O(n²) in the number of tools per turn.
166
+
167
+ **Fix:** Use a hash-based index (tool name + arg hash) for O(1) lookup instead of linear scan.
168
+
169
+ ---
170
+
171
+ ### 12. `ollama-pool.ts:1697` — Stale process cleanup timer
172
+
173
+ ```typescript
174
+ const handle = setTimeout(async () => {
175
+ const { cleanupStaleOllamaProcesses } = await import("./ollama-pool-cleanup.js");
176
+ const report = await cleanupStaleOllamaProcesses({ ... });
177
+ }, ...);
178
+ ```
179
+
180
+ **Problem:** Cleanup runs as a deferred `setTimeout` — adds latency before stale processes are actually cleaned up.
181
+
182
+ **Fix:** Run cleanup eagerly when a slot is freed, not on a timer.
183
+
184
+ ---
185
+
186
+ ### 13. `ollama-pool.ts:298,304` — `execSync` with 3s timeout
187
+
188
+ ```typescript
189
+ { encoding: "utf8", timeout: 3_000 },
190
+ ```
191
+
192
+ **Problem:** Synchronous child processes block the event loop. If the command takes the full 3s, the entire process stalls.
193
+
194
+ **Fix:** Use `execFile` with `Promise` wrapper or `spawn` with timeout signal.
195
+
196
+ ---
197
+
198
+ ### 14. `preflightSnapshot.ts:284,311` — Multiple 1.5s probe timeouts
199
+
200
+ ```typescript
201
+ timeout: 1500
202
+ ```
203
+
204
+ **Problem:** Preflight checks run multiple probes, each with 1.5s timeout. If multiple probes fail, this adds 3-6s of startup delay.
205
+
206
+ **Fix:** Run probes in parallel with `Promise.allSettled()` and use the first success.
207
+
208
+ ---
209
+
210
+ ### 15. `tool-batching.ts:212-240` — Concurrency limit on reads
211
+
212
+ ```typescript
213
+ export async function withConcurrencyLimit<T>(...) {
214
+ // Uses a limiter to cap parallel reads
215
+ }
216
+ ```
217
+
218
+ **Problem:** Concurrent-safe tools (reads) are limited by a concurrency cap. If the limit is too low, parallel reads are serialized unnecessarily.
219
+
220
+ **Fix:** Make the concurrency limit configurable and increase the default (e.g., from 2 to 8).
221
+
222
+ ---
223
+
224
+ ## Summary: Top 3 Fixes for Immediate Impact
225
+
226
+ | Priority | File | Change | Expected Savings |
227
+ |----------|------|--------|------------------|
228
+ | 1 | `streaming-executor.ts` | Replace 1ms spin loop with Promise notification | Eliminates busy-poll latency entirely |
229
+ | 2 | `ollama-pool.ts` | Cache GPU detection with 30s TTL | Eliminates 10-100ms per request |
230
+ | 3 | `cascadeBackend.ts` | Parallelize backend fallbacks with `Promise.race()` | Eliminates cascading timeout accumulation |
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.267",
3
+ "version": "1.0.268",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.267",
9
+ "version": "1.0.268",
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.267",
3
+ "version": "1.0.268",
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",