omnius 1.0.266 → 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 +379 -299
- package/docs/operations/delay-analysis.md +230 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
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 =
|
|
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({
|
|
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
|
|
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, {
|
|
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`, {
|
|
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
|
|
581411
|
-
if (
|
|
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
|
-
|
|
581416
|
-
|
|
581417
|
-
|
|
581418
|
-
|
|
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
|
|
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
|
|
581423
|
-
this.consecutiveFailures
|
|
581424
|
-
throw
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
596085
|
-
|
|
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 = {
|
|
@@ -606213,7 +606443,10 @@ var init_status_bar = __esm({
|
|
|
606213
606443
|
const sentinel = `${this.DYNAMIC_BLOCK_MARK_PREFIX}${id}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
|
|
606214
606444
|
this._contentLines.push(sentinel);
|
|
606215
606445
|
if (this._contentLines.length > this._contentMaxLines) {
|
|
606216
|
-
this._contentLines.splice(
|
|
606446
|
+
this._contentLines.splice(
|
|
606447
|
+
0,
|
|
606448
|
+
this._contentLines.length - this._contentMaxLines
|
|
606449
|
+
);
|
|
606217
606450
|
this.clampContentScrollOffset();
|
|
606218
606451
|
}
|
|
606219
606452
|
if (this._autoScroll && !this._mouseSelecting)
|
|
@@ -606346,8 +606579,13 @@ var init_status_bar = __esm({
|
|
|
606346
606579
|
];
|
|
606347
606580
|
const model = this.summarizeHeaderModelName();
|
|
606348
606581
|
const transport = this.summarizeHeaderTransport();
|
|
606349
|
-
if (model)
|
|
606350
|
-
|
|
606582
|
+
if (model)
|
|
606583
|
+
parts.push({ text: ` ${model} `, width: stripAnsi(` ${model} `).length });
|
|
606584
|
+
if (transport)
|
|
606585
|
+
parts.push({
|
|
606586
|
+
text: ` ${transport} `,
|
|
606587
|
+
width: stripAnsi(` ${transport} `).length
|
|
606588
|
+
});
|
|
606351
606589
|
if (this._updateLatest) {
|
|
606352
606590
|
const last2 = parts[parts.length - 1];
|
|
606353
606591
|
if (last2) {
|
|
@@ -606566,7 +606804,10 @@ var init_status_bar = __esm({
|
|
|
606566
606804
|
const telegramDot = this._telegramStatus.active ? "●" : "○";
|
|
606567
606805
|
const telegramLabel = this._telegramStatus.activeSubAgents > 0 ? ` ✈ tg ${this._telegramStatus.activeSubAgents} ` : " ✈ tg ";
|
|
606568
606806
|
sysItems.push({
|
|
606569
|
-
render: () => renderBtn(
|
|
606807
|
+
render: () => renderBtn(
|
|
606808
|
+
"telegram",
|
|
606809
|
+
`\x1B[38;5;45m${telegramDot}${telegramLabel}\x1B[0m`
|
|
606810
|
+
) + " ",
|
|
606570
606811
|
w: telegramLabel.length + 2
|
|
606571
606812
|
});
|
|
606572
606813
|
const nexusDot = this._nexusStatus === "connected" || this._nexusStatus === "connecting" ? "●" : "○";
|
|
@@ -607094,7 +607335,9 @@ var init_status_bar = __esm({
|
|
|
607094
607335
|
Promise.resolve().then(() => (init_dist8(), dist_exports3)).then(({ getOllamaPool: getOllamaPool2, resolveDefaultPoolConfig: resolveDefaultPoolConfig2 }) => {
|
|
607095
607336
|
try {
|
|
607096
607337
|
const config = resolveDefaultPoolConfig2();
|
|
607097
|
-
const pool3 = getOllamaPool2({
|
|
607338
|
+
const pool3 = getOllamaPool2({
|
|
607339
|
+
baseInstanceUrl: config.baseInstanceUrl
|
|
607340
|
+
});
|
|
607098
607341
|
broker.setOllamaAffinityProvider((modelName) => {
|
|
607099
607342
|
try {
|
|
607100
607343
|
const status = pool3.status?.();
|
|
@@ -607670,7 +607913,10 @@ var init_status_bar = __esm({
|
|
|
607670
607913
|
if (!this._mouseTrackingEnabled) return;
|
|
607671
607914
|
this._mouseTrackingEnabled = false;
|
|
607672
607915
|
if (process.stdout.isTTY) {
|
|
607673
|
-
this._trueStdoutWrite.call(
|
|
607916
|
+
this._trueStdoutWrite.call(
|
|
607917
|
+
process.stdout,
|
|
607918
|
+
"\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l"
|
|
607919
|
+
);
|
|
607674
607920
|
}
|
|
607675
607921
|
}
|
|
607676
607922
|
/** Re-apply the current mouse preference after overlays, password prompts, or redraws. */
|
|
@@ -608474,10 +608720,7 @@ ${CONTENT_BG_SEQ}`);
|
|
|
608474
608720
|
reflowContentLine(line, width) {
|
|
608475
608721
|
const visible = stripAnsi(line);
|
|
608476
608722
|
if (visible.length <= width) return [line];
|
|
608477
|
-
const continuationIndent = this.hangingIndentForVisibleLine(
|
|
608478
|
-
visible,
|
|
608479
|
-
width
|
|
608480
|
-
);
|
|
608723
|
+
const continuationIndent = this.hangingIndentForVisibleLine(visible, width);
|
|
608481
608724
|
const ranges = this.visibleWrapRanges(
|
|
608482
608725
|
visible,
|
|
608483
608726
|
width,
|
|
@@ -608650,46 +608893,28 @@ ${CONTENT_BG_SEQ}`);
|
|
|
608650
608893
|
(line) => line.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1B\]?[^\x07]*\x07/g, "")
|
|
608651
608894
|
);
|
|
608652
608895
|
const text2 = stripped.join("\n");
|
|
608653
|
-
|
|
608654
|
-
|
|
608655
|
-
|
|
608656
|
-
["xsel", "--clipboard", "--input"]
|
|
608657
|
-
];
|
|
608658
|
-
let success = false;
|
|
608659
|
-
for (const [cmd, ...args] of clipboardCmds) {
|
|
608896
|
+
if (text2.length === 0) return;
|
|
608897
|
+
const ok3 = copyText(text2);
|
|
608898
|
+
if (!ok3) {
|
|
608660
608899
|
try {
|
|
608661
|
-
const
|
|
608662
|
-
const
|
|
608663
|
-
|
|
608664
|
-
|
|
608665
|
-
|
|
608666
|
-
|
|
608667
|
-
|
|
608668
|
-
|
|
608669
|
-
|
|
608670
|
-
|
|
608671
|
-
|
|
608672
|
-
setTimeout(() => {
|
|
608673
|
-
if (!success) {
|
|
608674
|
-
try {
|
|
608675
|
-
child.kill();
|
|
608676
|
-
} catch {
|
|
608677
|
-
}
|
|
608678
|
-
}
|
|
608679
|
-
}, 500);
|
|
608680
|
-
break;
|
|
608900
|
+
const fs11 = __require("fs");
|
|
608901
|
+
const os9 = __require("os");
|
|
608902
|
+
const tmpPath = __require("path").join(
|
|
608903
|
+
os9.tmpdir(),
|
|
608904
|
+
"omnius-session-copy.txt"
|
|
608905
|
+
);
|
|
608906
|
+
fs11.writeFileSync(tmpPath, text2, "utf-8");
|
|
608907
|
+
process.stderr.write(
|
|
608908
|
+
`\x1B[38;5;208mClipboard unavailable — session saved to ${tmpPath}\x1B[0m
|
|
608909
|
+
`
|
|
608910
|
+
);
|
|
608681
608911
|
} catch {
|
|
608682
|
-
|
|
608912
|
+
process.stderr.write(
|
|
608913
|
+
`\x1B[38;5;196mFailed to save session to clipboard or temp file.\x1B[0m
|
|
608914
|
+
`
|
|
608915
|
+
);
|
|
608683
608916
|
}
|
|
608684
608917
|
}
|
|
608685
|
-
if (!success) {
|
|
608686
|
-
const fs11 = __require("fs");
|
|
608687
|
-
const os9 = __require("os");
|
|
608688
|
-
const tmpPath = __require("path").join(os9.tmpdir(), "omnius-session-copy.txt");
|
|
608689
|
-
fs11.writeFileSync(tmpPath, text2, "utf-8");
|
|
608690
|
-
process.stderr.write(`\x1B[38;5;208mClipboard unavailable — session saved to ${tmpPath}\x1B[0m
|
|
608691
|
-
`);
|
|
608692
|
-
}
|
|
608693
608918
|
}
|
|
608694
608919
|
/**
|
|
608695
608920
|
* WO-TASK-02 — sync the tasks panel "pager" scope flag with the current
|
|
@@ -608757,7 +608982,10 @@ ${CONTENT_BG_SEQ}`);
|
|
|
608757
608982
|
end: startCol + label.length - 1
|
|
608758
608983
|
};
|
|
608759
608984
|
const copyLabel = " ⎘ copy session ";
|
|
608760
|
-
const copyCol = Math.max(
|
|
608985
|
+
const copyCol = Math.max(
|
|
608986
|
+
startCol + label.length + 2,
|
|
608987
|
+
w - copyLabel.length
|
|
608988
|
+
);
|
|
608761
608989
|
if (copyCol + copyLabel.length <= w) {
|
|
608762
608990
|
buf += `\x1B[${spacerRow};${copyCol}H\x1B[38;5;141m${copyLabel}\x1B[0m${CONTENT_BG_SEQ}`;
|
|
608763
608991
|
this._copyBtnRegion = {
|
|
@@ -609268,7 +609496,10 @@ ${CONTENT_BG_SEQ}`);
|
|
|
609268
609496
|
if (!this.inputStateProvider) return 1;
|
|
609269
609497
|
const availWidth = this.inputTextWidth(termWidth);
|
|
609270
609498
|
const { line } = this.inputStateProvider();
|
|
609271
|
-
return Math.max(
|
|
609499
|
+
return Math.max(
|
|
609500
|
+
1,
|
|
609501
|
+
this.wrapPlainInputText(line, availWidth).rawLines.length
|
|
609502
|
+
);
|
|
609272
609503
|
}
|
|
609273
609504
|
/** Update _currentFooterHeight based on current input + suggestions. Returns true if height changed. */
|
|
609274
609505
|
updateFooterHeight(termWidth) {
|
|
@@ -609344,10 +609575,16 @@ ${CONTENT_BG_SEQ}`);
|
|
|
609344
609575
|
cursorRow: 0,
|
|
609345
609576
|
// Align with bordered input layout: col1 is │, content starts at col2.
|
|
609346
609577
|
// Keep this consistent with the wrapped path (+2) and positionAtInput().
|
|
609347
|
-
cursorCol: Math.min(
|
|
609578
|
+
cursorCol: Math.min(
|
|
609579
|
+
Math.max(1, termWidth - 1),
|
|
609580
|
+
this.promptWidth + cursorPos + 2
|
|
609581
|
+
)
|
|
609348
609582
|
};
|
|
609349
609583
|
}
|
|
609350
|
-
const { rawLines, charPositions } = this.wrapPlainInputText(
|
|
609584
|
+
const { rawLines, charPositions } = this.wrapPlainInputText(
|
|
609585
|
+
fullLine,
|
|
609586
|
+
availWidth
|
|
609587
|
+
);
|
|
609351
609588
|
let cursorLineIdx = rawLines.length - 1;
|
|
609352
609589
|
let cursorColInLine = cursorPos;
|
|
609353
609590
|
for (let i2 = 0; i2 < charPositions.length; i2++) {
|
|
@@ -609366,7 +609603,10 @@ ${CONTENT_BG_SEQ}`);
|
|
|
609366
609603
|
lines,
|
|
609367
609604
|
cursorRow: cursorLineIdx,
|
|
609368
609605
|
// +2 accounts for the left box border (│ at col 1) and the column after it
|
|
609369
|
-
cursorCol: Math.min(
|
|
609606
|
+
cursorCol: Math.min(
|
|
609607
|
+
Math.max(1, termWidth - 1),
|
|
609608
|
+
this.promptWidth + cursorColInLine + 2
|
|
609609
|
+
)
|
|
609370
609610
|
};
|
|
609371
609611
|
}
|
|
609372
609612
|
/** Set the DECSTBM scroll region to exclude the dynamic footer rows */
|
|
@@ -609543,7 +609783,8 @@ ${CONTENT_BG_SEQ}`);
|
|
|
609543
609783
|
* If footer height changed, also updates DECSTBM and redraws full footer.
|
|
609544
609784
|
*/
|
|
609545
609785
|
renderInputRowDuringStream(force = false) {
|
|
609546
|
-
if (!this.active || this._resizing && !force || !this.inputStateProvider)
|
|
609786
|
+
if (!this.active || this._resizing && !force || !this.inputStateProvider)
|
|
609787
|
+
return;
|
|
609547
609788
|
const rows = termRows();
|
|
609548
609789
|
const w = getTermWidth();
|
|
609549
609790
|
const oldFooterHeight = this._currentFooterHeight;
|
|
@@ -609992,7 +610233,11 @@ ${CONTENT_BG_SEQ}`);
|
|
|
609992
610233
|
totalToolCalls: this._toolCalls,
|
|
609993
610234
|
successfulToolCalls: this._successfulToolCalls,
|
|
609994
610235
|
failedToolCalls: this._failedToolCalls,
|
|
609995
|
-
toolCallBreakdown: this._toolCallBreakdown.map((t2) => ({
|
|
610236
|
+
toolCallBreakdown: this._toolCallBreakdown.map((t2) => ({
|
|
610237
|
+
name: t2.name,
|
|
610238
|
+
count: t2.count,
|
|
610239
|
+
avgDurationMs: 0
|
|
610240
|
+
})),
|
|
609996
610241
|
contextWindowSize: m2.contextWindowSize,
|
|
609997
610242
|
estimatedContextTokens: m2.estimatedContextTokens,
|
|
609998
610243
|
peakContextTokens: m2.estimatedContextTokens,
|
|
@@ -610013,10 +610258,10 @@ ${CONTENT_BG_SEQ}`);
|
|
|
610013
610258
|
// packages/cli/src/tui/tui-select.ts
|
|
610014
610259
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
610015
610260
|
function ansi3(code8, text2) {
|
|
610016
|
-
return
|
|
610261
|
+
return isTTY3 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
|
|
610017
610262
|
}
|
|
610018
610263
|
function fg2563(code8, text2) {
|
|
610019
|
-
return
|
|
610264
|
+
return isTTY3 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
|
|
610020
610265
|
}
|
|
610021
610266
|
function stripAnsi3(s2) {
|
|
610022
610267
|
return s2.replace(/\x1B\[[0-9;]*m/g, "");
|
|
@@ -610669,14 +610914,14 @@ ${tuiBgSeq()}`);
|
|
|
610669
610914
|
}
|
|
610670
610915
|
});
|
|
610671
610916
|
}
|
|
610672
|
-
var
|
|
610917
|
+
var isTTY3, MENU_ACTIVE_GREEN_256, selectColors, nonInteractiveSelectSurface;
|
|
610673
610918
|
var init_tui_select = __esm({
|
|
610674
610919
|
"packages/cli/src/tui/tui-select.ts"() {
|
|
610675
610920
|
"use strict";
|
|
610676
610921
|
init_overlay_lock();
|
|
610677
610922
|
init_theme();
|
|
610678
610923
|
init_layout2();
|
|
610679
|
-
|
|
610924
|
+
isTTY3 = process.stdout.isTTY ?? false;
|
|
610680
610925
|
MENU_ACTIVE_GREEN_256 = 154;
|
|
610681
610926
|
selectColors = {
|
|
610682
610927
|
blue: (t2) => fg2563(39, t2),
|
|
@@ -616152,7 +616397,7 @@ var init_format = __esm({
|
|
|
616152
616397
|
import { existsSync as existsSync116 } from "node:fs";
|
|
616153
616398
|
import { extname as extname17, resolve as resolve55 } from "node:path";
|
|
616154
616399
|
function ansi4(code8, text2) {
|
|
616155
|
-
return
|
|
616400
|
+
return isTTY4 ? `\x1B[${code8}m${text2}\x1B[0m` : text2;
|
|
616156
616401
|
}
|
|
616157
616402
|
function stripAnsi4(s2) {
|
|
616158
616403
|
return s2.replace(/\x1B\[[0-9;]*m/g, "");
|
|
@@ -616323,13 +616568,13 @@ function showDropPanel(opts) {
|
|
|
616323
616568
|
render2();
|
|
616324
616569
|
});
|
|
616325
616570
|
}
|
|
616326
|
-
var
|
|
616571
|
+
var isTTY4, dc;
|
|
616327
616572
|
var init_drop_panel = __esm({
|
|
616328
616573
|
"packages/cli/src/tui/drop-panel.ts"() {
|
|
616329
616574
|
"use strict";
|
|
616330
616575
|
init_overlay_lock();
|
|
616331
616576
|
init_layout2();
|
|
616332
|
-
|
|
616577
|
+
isTTY4 = process.stdout.isTTY ?? false;
|
|
616333
616578
|
dc = {
|
|
616334
616579
|
bold: (t2) => ansi4("1", t2),
|
|
616335
616580
|
dim: (t2) => ansi4("38;5;250", t2),
|
|
@@ -618628,17 +618873,17 @@ import { tmpdir as tmpdir20 } from "node:os";
|
|
|
618628
618873
|
import { join as join131 } from "node:path";
|
|
618629
618874
|
import { execSync as execSync54 } from "node:child_process";
|
|
618630
618875
|
function isNeovimActive() {
|
|
618631
|
-
return
|
|
618876
|
+
return _state2 !== null && !_state2.cleanedUp;
|
|
618632
618877
|
}
|
|
618633
618878
|
function isNeovimFocused() {
|
|
618634
|
-
return
|
|
618879
|
+
return _state2?.focused ?? false;
|
|
618635
618880
|
}
|
|
618636
618881
|
function refocusNeovim() {
|
|
618637
|
-
if (!
|
|
618638
|
-
toggleFocus(
|
|
618882
|
+
if (!_state2 || _state2.cleanedUp || _state2.focused) return;
|
|
618883
|
+
toggleFocus(_state2);
|
|
618639
618884
|
}
|
|
618640
618885
|
async function startNeovimMode(opts) {
|
|
618641
|
-
if (
|
|
618886
|
+
if (_state2 && !_state2.cleanedUp) {
|
|
618642
618887
|
return "Neovim mode is already active. Use /neovim to exit first.";
|
|
618643
618888
|
}
|
|
618644
618889
|
let nvimPath;
|
|
@@ -618679,7 +618924,7 @@ async function startNeovimMode(opts) {
|
|
|
618679
618924
|
const ptyCols = opts.cols;
|
|
618680
618925
|
const topOffset = opts.topOffset ?? 0;
|
|
618681
618926
|
const ptyRows = Math.max(5, opts.contentRows);
|
|
618682
|
-
if (
|
|
618927
|
+
if (isTTY5) {
|
|
618683
618928
|
const L = layout();
|
|
618684
618929
|
const bottomBound = L.contentBottom;
|
|
618685
618930
|
process.stdout.write(
|
|
@@ -618728,7 +618973,7 @@ async function startNeovimMode(opts) {
|
|
|
618728
618973
|
installedFilteredListeners: [],
|
|
618729
618974
|
cleanedUp: false
|
|
618730
618975
|
};
|
|
618731
|
-
|
|
618976
|
+
_state2 = state;
|
|
618732
618977
|
const toolbarBtns = [];
|
|
618733
618978
|
{
|
|
618734
618979
|
const btns = [
|
|
@@ -618748,7 +618993,7 @@ async function startNeovimMode(opts) {
|
|
|
618748
618993
|
}
|
|
618749
618994
|
}
|
|
618750
618995
|
function renderToolbar() {
|
|
618751
|
-
if (!
|
|
618996
|
+
if (!isTTY5) return;
|
|
618752
618997
|
const L = layout();
|
|
618753
618998
|
const hdrRow = L.headerContent;
|
|
618754
618999
|
const fg2 = 252;
|
|
@@ -618809,7 +619054,7 @@ async function startNeovimMode(opts) {
|
|
|
618809
619054
|
stdin.setRawMode(true);
|
|
618810
619055
|
}
|
|
618811
619056
|
stdin.resume();
|
|
618812
|
-
if (
|
|
619057
|
+
if (isTTY5) {
|
|
618813
619058
|
process.stdout.write("\x1B[?1002h\x1B[?1006h");
|
|
618814
619059
|
}
|
|
618815
619060
|
state.stdinHandler = (data) => {
|
|
@@ -618876,12 +619121,12 @@ async function startNeovimMode(opts) {
|
|
|
618876
619121
|
return null;
|
|
618877
619122
|
}
|
|
618878
619123
|
function stopNeovimMode() {
|
|
618879
|
-
if (!
|
|
619124
|
+
if (!_state2 || _state2.cleanedUp) return Promise.resolve();
|
|
618880
619125
|
try {
|
|
618881
|
-
|
|
619126
|
+
_state2.pty?.write("\x1B:qa!\r");
|
|
618882
619127
|
} catch {
|
|
618883
619128
|
}
|
|
618884
|
-
const s2 =
|
|
619129
|
+
const s2 = _state2;
|
|
618885
619130
|
return new Promise((resolve70) => {
|
|
618886
619131
|
setTimeout(() => {
|
|
618887
619132
|
if (s2 && !s2.cleanedUp) {
|
|
@@ -618892,18 +619137,18 @@ function stopNeovimMode() {
|
|
|
618892
619137
|
});
|
|
618893
619138
|
}
|
|
618894
619139
|
function writeToNeovimOutput(text2) {
|
|
618895
|
-
if (!
|
|
619140
|
+
if (!_state2 || _state2.cleanedUp || !_state2.nvim || !_state2.outputChanId) return;
|
|
618896
619141
|
const normalized = text2.replace(/(?<!\r)\n/g, "\r\n");
|
|
618897
|
-
|
|
619142
|
+
_state2.nvim.request("nvim_chan_send", [_state2.outputChanId, normalized]).catch(() => {
|
|
618898
619143
|
});
|
|
618899
619144
|
}
|
|
618900
619145
|
async function notifyNeovimFileChange(filePath) {
|
|
618901
|
-
if (!
|
|
619146
|
+
if (!_state2 || _state2.cleanedUp || !_state2.nvim) return;
|
|
618902
619147
|
try {
|
|
618903
|
-
await
|
|
619148
|
+
await _state2.nvim.command("checktime");
|
|
618904
619149
|
if (filePath) {
|
|
618905
619150
|
const escaped = filePath.replace(/'/g, "''");
|
|
618906
|
-
await
|
|
619151
|
+
await _state2.nvim.command(
|
|
618907
619152
|
`if bufexists('${escaped}') | execute 'buffer ' . bufnr('${escaped}') | endif`
|
|
618908
619153
|
);
|
|
618909
619154
|
}
|
|
@@ -618911,10 +619156,10 @@ async function notifyNeovimFileChange(filePath) {
|
|
|
618911
619156
|
}
|
|
618912
619157
|
}
|
|
618913
619158
|
function resizeNeovim(cols, contentRows) {
|
|
618914
|
-
if (!
|
|
619159
|
+
if (!_state2 || _state2.cleanedUp || !_state2.pty) return;
|
|
618915
619160
|
const rows = Math.max(5, contentRows);
|
|
618916
619161
|
try {
|
|
618917
|
-
|
|
619162
|
+
_state2.pty.resize(cols, rows);
|
|
618918
619163
|
} catch {
|
|
618919
619164
|
}
|
|
618920
619165
|
}
|
|
@@ -619089,7 +619334,7 @@ function doCleanup(state) {
|
|
|
619089
619334
|
} catch {
|
|
619090
619335
|
}
|
|
619091
619336
|
}
|
|
619092
|
-
|
|
619337
|
+
_state2 = null;
|
|
619093
619338
|
process.stdout.write(
|
|
619094
619339
|
`\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?1004l\x1B[?2004l\x1B[1;${termRows()}r`
|
|
619095
619340
|
// reset scroll region to full terminal
|
|
@@ -619108,16 +619353,16 @@ function doCleanup(state) {
|
|
|
619108
619353
|
}
|
|
619109
619354
|
state.opts.onExit?.();
|
|
619110
619355
|
}
|
|
619111
|
-
var
|
|
619356
|
+
var isTTY5, PTY_MODE_ENABLE_RE, STDIN_MOUSE_FOCUS_RE, _state2;
|
|
619112
619357
|
var init_neovim_mode = __esm({
|
|
619113
619358
|
"packages/cli/src/tui/neovim-mode.ts"() {
|
|
619114
619359
|
"use strict";
|
|
619115
619360
|
init_setup();
|
|
619116
619361
|
init_layout2();
|
|
619117
|
-
|
|
619362
|
+
isTTY5 = process.stdout.isTTY ?? false;
|
|
619118
619363
|
PTY_MODE_ENABLE_RE = /\x1B\[\?(?:1004|2004)h/g;
|
|
619119
619364
|
STDIN_MOUSE_FOCUS_RE = /\x1B\[<[\d;]+[Mm]|\x1B\[M[\s\S]{3}|\x1B\[[IO]|\x1BO[ABCD]/g;
|
|
619120
|
-
|
|
619365
|
+
_state2 = null;
|
|
619121
619366
|
}
|
|
619122
619367
|
});
|
|
619123
619368
|
|
|
@@ -644051,7 +644296,7 @@ function setCarouselWriter(writer) {
|
|
|
644051
644296
|
chromeWrite2 = writer;
|
|
644052
644297
|
}
|
|
644053
644298
|
function fg(code8, text2) {
|
|
644054
|
-
return
|
|
644299
|
+
return isTTY6 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
|
|
644055
644300
|
}
|
|
644056
644301
|
function displayWidth(str) {
|
|
644057
644302
|
let w = 0;
|
|
@@ -644089,12 +644334,12 @@ function createRow(phraseIndices, speed, direction, bank2) {
|
|
|
644089
644334
|
const phrases = phraseIndices.map((i2) => bank2[i2 % bank2.length]);
|
|
644090
644335
|
return { phrases, offset: 0, speed, direction, renderedPlain: "" };
|
|
644091
644336
|
}
|
|
644092
|
-
var
|
|
644337
|
+
var isTTY6, chromeWrite2, PHRASES, Carousel;
|
|
644093
644338
|
var init_carousel = __esm({
|
|
644094
644339
|
"packages/cli/src/tui/carousel.ts"() {
|
|
644095
644340
|
"use strict";
|
|
644096
644341
|
init_layout2();
|
|
644097
|
-
|
|
644342
|
+
isTTY6 = process.stdout.isTTY ?? false;
|
|
644098
644343
|
chromeWrite2 = ((data) => {
|
|
644099
644344
|
process.stdout.write(data);
|
|
644100
644345
|
});
|
|
@@ -644206,7 +644451,7 @@ var init_carousel = __esm({
|
|
|
644206
644451
|
* Sets scroll region to row 5+ for all content/readline.
|
|
644207
644452
|
*/
|
|
644208
644453
|
start() {
|
|
644209
|
-
if (!
|
|
644454
|
+
if (!isTTY6) return 0;
|
|
644210
644455
|
this.started = true;
|
|
644211
644456
|
setHeaderHeight(this.reservedRows);
|
|
644212
644457
|
const L = layout();
|
|
@@ -644238,7 +644483,7 @@ var init_carousel = __esm({
|
|
|
644238
644483
|
* Row 4 is left blank as a separator.
|
|
644239
644484
|
*/
|
|
644240
644485
|
renderFrame() {
|
|
644241
|
-
if (!
|
|
644486
|
+
if (!isTTY6) return;
|
|
644242
644487
|
const L = layout();
|
|
644243
644488
|
let buf = "\x1B7";
|
|
644244
644489
|
buf += "\x1B[?7l";
|
|
@@ -644315,7 +644560,7 @@ var init_carousel = __esm({
|
|
|
644315
644560
|
process.stdout.removeListener("resize", this.resizeHandler);
|
|
644316
644561
|
this.resizeHandler = null;
|
|
644317
644562
|
}
|
|
644318
|
-
if (!
|
|
644563
|
+
if (!isTTY6 || !this.started) return;
|
|
644319
644564
|
const L = layout();
|
|
644320
644565
|
let buf = "\x1B7";
|
|
644321
644566
|
for (let i2 = 0; i2 < this.reservedRows; i2++) {
|
|
@@ -644551,13 +644796,13 @@ function createAnimatedBanner(id, name10, frameBuilders, frameDurationMs, author
|
|
|
644551
644796
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
644552
644797
|
};
|
|
644553
644798
|
}
|
|
644554
|
-
var
|
|
644799
|
+
var isTTY7, chromeWrite3, MNEMONIC_ADJECTIVES, MNEMONIC_NOUNS, BannerRenderer;
|
|
644555
644800
|
var init_banner = __esm({
|
|
644556
644801
|
"packages/cli/src/tui/banner.ts"() {
|
|
644557
644802
|
"use strict";
|
|
644558
644803
|
init_theme();
|
|
644559
644804
|
init_layout2();
|
|
644560
|
-
|
|
644805
|
+
isTTY7 = process.stdout.isTTY ?? false;
|
|
644561
644806
|
chromeWrite3 = ((data) => {
|
|
644562
644807
|
process.stdout.write(data);
|
|
644563
644808
|
});
|
|
@@ -644719,7 +644964,7 @@ var init_banner = __esm({
|
|
|
644719
644964
|
* Returns the number of rows reserved (3 banner + 1 separator = 4).
|
|
644720
644965
|
*/
|
|
644721
644966
|
start() {
|
|
644722
|
-
if (!
|
|
644967
|
+
if (!isTTY7 || !this.currentDesign) return 0;
|
|
644723
644968
|
this.renderCurrentFrame();
|
|
644724
644969
|
this._resizeHandler = () => {
|
|
644725
644970
|
setTermSize(process.stdout.rows ?? 24, process.stdout.columns ?? 80);
|
|
@@ -644760,7 +645005,7 @@ var init_banner = __esm({
|
|
|
644760
645005
|
}
|
|
644761
645006
|
/** Render the current frame into the top 3 rows (public for refresh callbacks) */
|
|
644762
645007
|
renderCurrentFrame() {
|
|
644763
|
-
if (!
|
|
645008
|
+
if (!isTTY7 || !this.currentDesign) return;
|
|
644764
645009
|
const frame = this.currentDesign.frames[this.currentFrame];
|
|
644765
645010
|
if (!frame) return;
|
|
644766
645011
|
this.width = termCols();
|
|
@@ -645164,175 +645409,6 @@ var init_carousel_descriptors = __esm({
|
|
|
645164
645409
|
}
|
|
645165
645410
|
});
|
|
645166
645411
|
|
|
645167
|
-
// packages/cli/src/tui/syntax-highlight.ts
|
|
645168
|
-
var syntax_highlight_exports = {};
|
|
645169
|
-
__export(syntax_highlight_exports, {
|
|
645170
|
-
detectLanguage: () => detectLanguage2,
|
|
645171
|
-
getHighlightStatus: () => getHighlightStatus,
|
|
645172
|
-
highlightBlock: () => highlightBlock,
|
|
645173
|
-
highlightCode: () => highlightCode,
|
|
645174
|
-
isAvailable: () => isAvailable,
|
|
645175
|
-
prewarm: () => prewarm
|
|
645176
|
-
});
|
|
645177
|
-
function highlightingDisabled() {
|
|
645178
|
-
return !isTTY7 || noColorEnv || disableEnv;
|
|
645179
|
-
}
|
|
645180
|
-
async function loadHighlighter() {
|
|
645181
|
-
if (_state2.attempted) return _state2.fn;
|
|
645182
|
-
_state2.attempted = true;
|
|
645183
|
-
if (highlightingDisabled()) {
|
|
645184
|
-
_state2.reason = !isTTY7 ? "non-tty" : noColorEnv ? "NO_COLOR set" : "OMNIUS_TUI_HIGHLIGHT=0";
|
|
645185
|
-
return null;
|
|
645186
|
-
}
|
|
645187
|
-
try {
|
|
645188
|
-
const { createRequire: createRequire10 } = await import("node:module");
|
|
645189
|
-
const req3 = createRequire10(import.meta.url);
|
|
645190
|
-
let resolved = null;
|
|
645191
|
-
try {
|
|
645192
|
-
resolved = req3.resolve("cli-highlight");
|
|
645193
|
-
} catch {
|
|
645194
|
-
_state2.reason = "cli-highlight not installed";
|
|
645195
|
-
return null;
|
|
645196
|
-
}
|
|
645197
|
-
const mod3 = await import(resolved).catch(() => null);
|
|
645198
|
-
if (!mod3) {
|
|
645199
|
-
_state2.reason = "cli-highlight failed to load";
|
|
645200
|
-
return null;
|
|
645201
|
-
}
|
|
645202
|
-
const m2 = mod3;
|
|
645203
|
-
const candidate = m2.highlight ?? m2.default ?? null;
|
|
645204
|
-
if (typeof candidate !== "function") {
|
|
645205
|
-
_state2.reason = "cli-highlight export shape unrecognized";
|
|
645206
|
-
return null;
|
|
645207
|
-
}
|
|
645208
|
-
_state2.fn = candidate;
|
|
645209
|
-
return candidate;
|
|
645210
|
-
} catch (err) {
|
|
645211
|
-
_state2.reason = `import threw: ${err?.message ?? String(err)}`;
|
|
645212
|
-
return null;
|
|
645213
|
-
}
|
|
645214
|
-
}
|
|
645215
|
-
function loadHighlighterSync() {
|
|
645216
|
-
if (highlightingDisabled()) return null;
|
|
645217
|
-
return _state2.fn;
|
|
645218
|
-
}
|
|
645219
|
-
async function prewarm() {
|
|
645220
|
-
await loadHighlighter();
|
|
645221
|
-
}
|
|
645222
|
-
function isAvailable() {
|
|
645223
|
-
if (highlightingDisabled()) return false;
|
|
645224
|
-
return _state2.attempted && _state2.fn !== null;
|
|
645225
|
-
}
|
|
645226
|
-
function getHighlightStatus() {
|
|
645227
|
-
return {
|
|
645228
|
-
available: isAvailable(),
|
|
645229
|
-
attempted: _state2.attempted,
|
|
645230
|
-
reason: _state2.reason,
|
|
645231
|
-
isTTY: isTTY7,
|
|
645232
|
-
noColor: noColorEnv,
|
|
645233
|
-
disabledByEnv: disableEnv
|
|
645234
|
-
};
|
|
645235
|
-
}
|
|
645236
|
-
function highlightCode(code8, language) {
|
|
645237
|
-
if (!code8) return code8;
|
|
645238
|
-
const fn = loadHighlighterSync();
|
|
645239
|
-
if (!fn) return code8;
|
|
645240
|
-
const lang = (language ?? detectLanguage2(code8) ?? "").trim();
|
|
645241
|
-
try {
|
|
645242
|
-
if (lang) {
|
|
645243
|
-
return fn(code8, { language: lang, ignoreIllegals: true });
|
|
645244
|
-
}
|
|
645245
|
-
return fn(code8, { ignoreIllegals: true });
|
|
645246
|
-
} catch {
|
|
645247
|
-
return code8;
|
|
645248
|
-
}
|
|
645249
|
-
}
|
|
645250
|
-
function detectLanguage2(text2) {
|
|
645251
|
-
if (!text2) return null;
|
|
645252
|
-
const trimmed = text2.trimStart();
|
|
645253
|
-
const shebang = trimmed.match(/^#!\s*\/[^\n]+/);
|
|
645254
|
-
if (shebang) {
|
|
645255
|
-
const sb = shebang[0];
|
|
645256
|
-
if (/python/.test(sb)) return "python";
|
|
645257
|
-
if (/(?:^|[\s/])(?:bash|sh|zsh)\b/.test(sb)) return "bash";
|
|
645258
|
-
if (/node/.test(sb)) return "javascript";
|
|
645259
|
-
if (/ruby/.test(sb)) return "ruby";
|
|
645260
|
-
if (/perl/.test(sb)) return "perl";
|
|
645261
|
-
}
|
|
645262
|
-
if (/^[\s\n]*[{[]/.test(trimmed)) {
|
|
645263
|
-
try {
|
|
645264
|
-
JSON.parse(trimmed);
|
|
645265
|
-
return "json";
|
|
645266
|
-
} catch {
|
|
645267
|
-
}
|
|
645268
|
-
}
|
|
645269
|
-
if (/^[-a-zA-Z_][\w-]*:\s/.test(trimmed) && /\n[-a-zA-Z_][\w-]*:\s/.test(trimmed)) {
|
|
645270
|
-
return "yaml";
|
|
645271
|
-
}
|
|
645272
|
-
if (/^(?:async def |def |class |import |from )/.test(trimmed) && /(?::\s*$|->|self\b)/m.test(trimmed)) {
|
|
645273
|
-
return "python";
|
|
645274
|
-
}
|
|
645275
|
-
if (/^(?:import |export |const |let |var |function |class |interface |type |async )/.test(trimmed)) {
|
|
645276
|
-
if (/(:\s*(?:string|number|boolean|any|unknown|void)\b|\binterface\b|\btype\s+\w+\s*=)/.test(trimmed)) {
|
|
645277
|
-
return "typescript";
|
|
645278
|
-
}
|
|
645279
|
-
return "javascript";
|
|
645280
|
-
}
|
|
645281
|
-
if (/(?:^|\n)\s*(?:fn |use |let mut |impl |struct |enum |trait )/.test(trimmed)) {
|
|
645282
|
-
return "rust";
|
|
645283
|
-
}
|
|
645284
|
-
if (/(?:^package \w+|\nfunc \w+\s*\()/.test(trimmed)) {
|
|
645285
|
-
return "go";
|
|
645286
|
-
}
|
|
645287
|
-
if (/^\s*(?:SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/i.test(trimmed)) {
|
|
645288
|
-
return "sql";
|
|
645289
|
-
}
|
|
645290
|
-
if (/^[\s\n]*<(?:!DOCTYPE|html|\?xml|\w+)/i.test(trimmed)) {
|
|
645291
|
-
return "html";
|
|
645292
|
-
}
|
|
645293
|
-
if (/^(?:---|\+\+\+|@@|diff )/.test(trimmed)) {
|
|
645294
|
-
return "diff";
|
|
645295
|
-
}
|
|
645296
|
-
if (/^\s*(?:\$\s|sudo |apt |brew |npm |pnpm |yarn |git |docker |kubectl |curl |wget )/.test(trimmed)) {
|
|
645297
|
-
return "bash";
|
|
645298
|
-
}
|
|
645299
|
-
return null;
|
|
645300
|
-
}
|
|
645301
|
-
function highlightBlock(code8, language) {
|
|
645302
|
-
if (!code8) return [""];
|
|
645303
|
-
const fn = loadHighlighterSync();
|
|
645304
|
-
if (!fn) return code8.split("\n");
|
|
645305
|
-
const lang = (language ?? detectLanguage2(code8) ?? "").trim();
|
|
645306
|
-
try {
|
|
645307
|
-
const out = lang ? fn(code8, { language: lang, ignoreIllegals: true }) : fn(code8, { ignoreIllegals: true });
|
|
645308
|
-
const lines = out.split("\n");
|
|
645309
|
-
const inputLines = code8.split("\n");
|
|
645310
|
-
if (lines.length === inputLines.length) return lines;
|
|
645311
|
-
if (lines.length < inputLines.length) {
|
|
645312
|
-
while (lines.length < inputLines.length) lines.push("");
|
|
645313
|
-
} else {
|
|
645314
|
-
lines.length = inputLines.length;
|
|
645315
|
-
}
|
|
645316
|
-
return lines;
|
|
645317
|
-
} catch {
|
|
645318
|
-
return code8.split("\n");
|
|
645319
|
-
}
|
|
645320
|
-
}
|
|
645321
|
-
var isTTY7, noColorEnv, disableEnv, _state2;
|
|
645322
|
-
var init_syntax_highlight = __esm({
|
|
645323
|
-
"packages/cli/src/tui/syntax-highlight.ts"() {
|
|
645324
|
-
"use strict";
|
|
645325
|
-
isTTY7 = process.stdout?.isTTY ?? false;
|
|
645326
|
-
noColorEnv = process.env["NO_COLOR"] !== void 0 && process.env["NO_COLOR"] !== "";
|
|
645327
|
-
disableEnv = process.env["OMNIUS_TUI_HIGHLIGHT"] === "0";
|
|
645328
|
-
_state2 = {
|
|
645329
|
-
attempted: false,
|
|
645330
|
-
fn: null,
|
|
645331
|
-
reason: ""
|
|
645332
|
-
};
|
|
645333
|
-
}
|
|
645334
|
-
});
|
|
645335
|
-
|
|
645336
645412
|
// packages/cli/src/tui/stream-renderer.ts
|
|
645337
645413
|
function fg2564(code8, text2) {
|
|
645338
645414
|
return isTTY8 ? `\x1B[38;5;${code8}m${text2}\x1B[0m` : text2;
|
|
@@ -704310,28 +704386,32 @@ ${entry.fullContent}`
|
|
|
704310
704386
|
}
|
|
704311
704387
|
if (lm.intervention) {
|
|
704312
704388
|
contentWrite(() => {
|
|
704313
|
-
|
|
704314
|
-
if (lm.details && showAdversary) {
|
|
704315
|
-
const det = String(lm.details);
|
|
704316
|
-
lines.push(...det.split("\n").filter(Boolean));
|
|
704317
|
-
}
|
|
704318
|
-
renderBoxedBlock({
|
|
704319
|
-
title: "Adversary",
|
|
704320
|
-
lines,
|
|
704321
|
-
kind: "plain"
|
|
704322
|
-
});
|
|
704389
|
+
renderWarning(`Adversary: ${lm.intervention}`);
|
|
704323
704390
|
});
|
|
704324
704391
|
} else if (lm.details && showAdversary) {
|
|
704325
704392
|
contentWrite(() => {
|
|
704326
|
-
|
|
704327
|
-
|
|
704328
|
-
|
|
704329
|
-
kind: "dim"
|
|
704330
|
-
});
|
|
704393
|
+
renderInfo(
|
|
704394
|
+
`Adversary details: ${String(lm.details).split("\n").filter(Boolean).join(" | ")}`
|
|
704395
|
+
);
|
|
704331
704396
|
});
|
|
704332
704397
|
}
|
|
704333
704398
|
}
|
|
704334
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;
|
|
704335
704415
|
}
|
|
704336
704416
|
});
|
|
704337
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 |
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
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.
|
|
9
|
+
"version": "1.0.268",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED