omnius 1.0.4 → 1.0.6
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 +715 -70
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -250369,10 +250369,19 @@ function inferImageGenerationBackend(model, requested) {
|
|
|
250369
250369
|
return "sdcpp";
|
|
250370
250370
|
return "diffusers";
|
|
250371
250371
|
}
|
|
250372
|
+
function imageGenerationDir(repoRoot = ".") {
|
|
250373
|
+
return join36(repoRoot, ".omnius", "image-gen");
|
|
250374
|
+
}
|
|
250375
|
+
function diffusersVenvDir(repoRoot = ".") {
|
|
250376
|
+
return join36(imageGenerationDir(repoRoot), ".venv");
|
|
250377
|
+
}
|
|
250378
|
+
function sdcppVenvDir(repoRoot = ".") {
|
|
250379
|
+
return join36(imageGenerationDir(repoRoot), ".venv-sdcpp");
|
|
250380
|
+
}
|
|
250372
250381
|
function imageGenerationSetupPlan(backend, repoRoot = ".", model) {
|
|
250373
|
-
const imageDir =
|
|
250382
|
+
const imageDir = imageGenerationDir(repoRoot);
|
|
250374
250383
|
if (backend === "ollama") {
|
|
250375
|
-
const chosen = model && model !== "auto" ? model :
|
|
250384
|
+
const chosen = model && model !== "auto" ? model : DEFAULT_OLLAMA_IMAGE_MODEL;
|
|
250376
250385
|
return {
|
|
250377
250386
|
backend,
|
|
250378
250387
|
title: "Ollama image generation",
|
|
@@ -250387,26 +250396,30 @@ function imageGenerationSetupPlan(backend, repoRoot = ".", model) {
|
|
|
250387
250396
|
};
|
|
250388
250397
|
}
|
|
250389
250398
|
if (backend === "diffusers") {
|
|
250399
|
+
const venvDir2 = diffusersVenvDir(repoRoot);
|
|
250400
|
+
const chosen = model && model !== "auto" ? model : DEFAULT_DIFFUSERS_IMAGE_MODEL;
|
|
250390
250401
|
return {
|
|
250391
250402
|
backend,
|
|
250392
250403
|
title: "Python Diffusers image generation",
|
|
250393
250404
|
commands: [
|
|
250394
|
-
`python3 -m venv ${
|
|
250395
|
-
`${
|
|
250396
|
-
`omnius /image "a compact robot painter" --backend diffusers --model ${
|
|
250405
|
+
`python3 -m venv ${venvDir2}`,
|
|
250406
|
+
`${venvPython(venvDir2)} -m pip install -U pip ${DIFFUSERS_PYTHON_PACKAGES.join(" ")}`,
|
|
250407
|
+
`omnius /image "a compact robot painter" --backend diffusers --model ${chosen}`
|
|
250397
250408
|
],
|
|
250398
250409
|
notes: [
|
|
250399
|
-
|
|
250410
|
+
`Default first-run model: ${DEFAULT_DIFFUSERS_IMAGE_MODEL}. Good lighter candidates: stabilityai/sd-turbo, segmind/tiny-sd, nota-ai/bk-sdm-tiny-2m.`,
|
|
250411
|
+
"The venv, Hugging Face cache, Torch cache, and pip cache stay under .omnius/image-gen.",
|
|
250400
250412
|
"The runner script is created automatically at .omnius/image-gen/diffusers_text2image.py."
|
|
250401
250413
|
]
|
|
250402
250414
|
};
|
|
250403
250415
|
}
|
|
250416
|
+
const venvDir = sdcppVenvDir(repoRoot);
|
|
250404
250417
|
return {
|
|
250405
250418
|
backend,
|
|
250406
250419
|
title: "stable-diffusion.cpp Python image generation",
|
|
250407
250420
|
commands: [
|
|
250408
|
-
`python3 -m venv ${
|
|
250409
|
-
`${
|
|
250421
|
+
`python3 -m venv ${venvDir}`,
|
|
250422
|
+
`${venvPython(venvDir)} -m pip install -U pip ${SDCPP_PYTHON_PACKAGES.join(" ")}`,
|
|
250410
250423
|
`omnius /image "a compact robot painter" --backend sdcpp --model /absolute/path/to/model.gguf`
|
|
250411
250424
|
],
|
|
250412
250425
|
notes: [
|
|
@@ -250450,17 +250463,75 @@ function trimProcessText(text, max = 1800) {
|
|
|
250450
250463
|
return clean3;
|
|
250451
250464
|
return clean3.slice(0, max - 20) + "\n... (truncated)";
|
|
250452
250465
|
}
|
|
250453
|
-
function
|
|
250466
|
+
function imageGenerationPythonEnv(repoRoot) {
|
|
250467
|
+
const root = imageGenerationDir(repoRoot);
|
|
250468
|
+
const hf = join36(root, "huggingface");
|
|
250469
|
+
return {
|
|
250470
|
+
PYTHONUNBUFFERED: "1",
|
|
250471
|
+
HF_HOME: hf,
|
|
250472
|
+
HUGGINGFACE_HUB_CACHE: join36(hf, "hub"),
|
|
250473
|
+
TRANSFORMERS_CACHE: join36(hf, "transformers"),
|
|
250474
|
+
DIFFUSERS_CACHE: join36(hf, "diffusers"),
|
|
250475
|
+
TORCH_HOME: join36(root, "torch"),
|
|
250476
|
+
XDG_CACHE_HOME: join36(root, "cache"),
|
|
250477
|
+
PIP_CACHE_DIR: join36(root, "pip-cache")
|
|
250478
|
+
};
|
|
250479
|
+
}
|
|
250480
|
+
async function ensureImageGenerationCacheDirs(repoRoot) {
|
|
250481
|
+
const env2 = imageGenerationPythonEnv(repoRoot);
|
|
250482
|
+
await Promise.all([
|
|
250483
|
+
imageGenerationDir(repoRoot),
|
|
250484
|
+
env2["HF_HOME"],
|
|
250485
|
+
env2["HUGGINGFACE_HUB_CACHE"],
|
|
250486
|
+
env2["TRANSFORMERS_CACHE"],
|
|
250487
|
+
env2["DIFFUSERS_CACHE"],
|
|
250488
|
+
env2["TORCH_HOME"],
|
|
250489
|
+
env2["XDG_CACHE_HOME"],
|
|
250490
|
+
env2["PIP_CACHE_DIR"]
|
|
250491
|
+
].filter((value2) => Boolean(value2)).map((dir) => mkdir11(dir, { recursive: true })));
|
|
250492
|
+
}
|
|
250493
|
+
async function pythonCanImport(command, code8, repoRoot, env2) {
|
|
250494
|
+
const result = await runProcess2(command, ["-c", code8], { cwd: repoRoot, timeoutMs: 6e4, env: env2 });
|
|
250495
|
+
return result.code === 0;
|
|
250496
|
+
}
|
|
250497
|
+
async function ensurePythonFor(repoRoot, kind, explicit) {
|
|
250498
|
+
const pythonEnv = imageGenerationPythonEnv(repoRoot);
|
|
250499
|
+
await ensureImageGenerationCacheDirs(repoRoot);
|
|
250454
250500
|
if (explicit)
|
|
250455
|
-
return explicit;
|
|
250456
|
-
const
|
|
250457
|
-
if (
|
|
250458
|
-
return
|
|
250459
|
-
const
|
|
250460
|
-
|
|
250501
|
+
return { command: explicit, env: pythonEnv };
|
|
250502
|
+
const configuredPython = process.env["OMNIUS_IMAGE_PYTHON"];
|
|
250503
|
+
if (configuredPython)
|
|
250504
|
+
return { command: configuredPython, env: pythonEnv };
|
|
250505
|
+
const venvDir = kind === "diffusers" ? diffusersVenvDir(repoRoot) : sdcppVenvDir(repoRoot);
|
|
250506
|
+
const command = venvPython(venvDir);
|
|
250507
|
+
if (!existsSync23(command)) {
|
|
250508
|
+
const created = await runProcess2("python3", ["-m", "venv", venvDir], { cwd: repoRoot, timeoutMs: 18e4, env: pythonEnv });
|
|
250509
|
+
if (created.code !== 0) {
|
|
250510
|
+
throw new Error(`Failed to create image-generation venv at ${venvDir}.
|
|
250511
|
+
${trimProcessText(created.stderr || created.stdout)}`);
|
|
250512
|
+
}
|
|
250513
|
+
}
|
|
250514
|
+
const importCheck = kind === "diffusers" ? "import torch, diffusers, PIL\nfrom diffusers import AutoPipelineForText2Image\n" : "import stable_diffusion_cpp, PIL\n";
|
|
250515
|
+
if (await pythonCanImport(command, importCheck, repoRoot, pythonEnv)) {
|
|
250516
|
+
return { command, env: pythonEnv };
|
|
250517
|
+
}
|
|
250518
|
+
const packages = kind === "diffusers" ? DIFFUSERS_PYTHON_PACKAGES : SDCPP_PYTHON_PACKAGES;
|
|
250519
|
+
const pip = await runProcess2(command, ["-m", "pip", "install", "-U", "pip", ...packages], {
|
|
250520
|
+
cwd: repoRoot,
|
|
250521
|
+
timeoutMs: 18e5,
|
|
250522
|
+
env: pythonEnv
|
|
250523
|
+
});
|
|
250524
|
+
if (pip.code !== 0) {
|
|
250525
|
+
throw new Error(`Failed to install ${kind} image-generation packages into ${venvDir}.
|
|
250526
|
+
${trimProcessText(pip.stderr || pip.stdout)}`);
|
|
250527
|
+
}
|
|
250528
|
+
if (!await pythonCanImport(command, importCheck, repoRoot, pythonEnv)) {
|
|
250529
|
+
throw new Error(`Image-generation Python environment at ${venvDir} was created, but required ${kind} imports still fail.`);
|
|
250530
|
+
}
|
|
250531
|
+
return { command, env: pythonEnv };
|
|
250461
250532
|
}
|
|
250462
250533
|
async function ensureRunner(repoRoot, kind) {
|
|
250463
|
-
const dir =
|
|
250534
|
+
const dir = imageGenerationDir(repoRoot);
|
|
250464
250535
|
await mkdir11(dir, { recursive: true });
|
|
250465
250536
|
const script = kind === "diffusers" ? join36(dir, "diffusers_text2image.py") : join36(dir, "sdcpp_text2image.py");
|
|
250466
250537
|
await writeFile16(script, kind === "diffusers" ? DIFFUSERS_RUNNER : SDCPP_RUNNER, "utf8");
|
|
@@ -250494,16 +250565,39 @@ function parseRunnerJson(stdout) {
|
|
|
250494
250565
|
}
|
|
250495
250566
|
return null;
|
|
250496
250567
|
}
|
|
250497
|
-
var IMAGE_GENERATION_MODEL_PRESETS, OLLAMA_IMAGE_MODELS, DIFFUSERS_RUNNER, SDCPP_RUNNER, ImageGenerateTool;
|
|
250568
|
+
var DEFAULT_DIFFUSERS_IMAGE_MODEL, DEFAULT_OLLAMA_IMAGE_MODEL, DIFFUSERS_PYTHON_PACKAGES, SDCPP_PYTHON_PACKAGES, IMAGE_GENERATION_MODEL_PRESETS, OLLAMA_IMAGE_MODELS, DIFFUSERS_RUNNER, SDCPP_RUNNER, ImageGenerateTool;
|
|
250498
250569
|
var init_image_generate = __esm({
|
|
250499
250570
|
"packages/execution/dist/tools/image-generate.js"() {
|
|
250500
250571
|
"use strict";
|
|
250572
|
+
init_venv_paths();
|
|
250573
|
+
DEFAULT_DIFFUSERS_IMAGE_MODEL = "stabilityai/sdxl-turbo";
|
|
250574
|
+
DEFAULT_OLLAMA_IMAGE_MODEL = "x/z-image-turbo";
|
|
250575
|
+
DIFFUSERS_PYTHON_PACKAGES = [
|
|
250576
|
+
"torch",
|
|
250577
|
+
"diffusers",
|
|
250578
|
+
"transformers",
|
|
250579
|
+
"accelerate",
|
|
250580
|
+
"safetensors",
|
|
250581
|
+
"pillow",
|
|
250582
|
+
"sentencepiece",
|
|
250583
|
+
"protobuf"
|
|
250584
|
+
];
|
|
250585
|
+
SDCPP_PYTHON_PACKAGES = [
|
|
250586
|
+
"stable-diffusion-cpp-python",
|
|
250587
|
+
"pillow"
|
|
250588
|
+
];
|
|
250501
250589
|
IMAGE_GENERATION_MODEL_PRESETS = [
|
|
250502
250590
|
{
|
|
250503
|
-
id:
|
|
250591
|
+
id: DEFAULT_OLLAMA_IMAGE_MODEL,
|
|
250504
250592
|
label: "Z-Image Turbo",
|
|
250505
250593
|
backend: "ollama",
|
|
250506
250594
|
install: "ollama pull x/z-image-turbo",
|
|
250595
|
+
category: "Modern deployable",
|
|
250596
|
+
sizeClass: "6B-class efficient image model",
|
|
250597
|
+
quality: "Modern high-quality output with a practical inference footprint; below FLUX.1 dev/SD3.5 Large for peak photorealism.",
|
|
250598
|
+
minVramGB: 16,
|
|
250599
|
+
recommendedVramGB: 24,
|
|
250600
|
+
deployment: "Ollama model path; good high-end consumer GPU target.",
|
|
250507
250601
|
steps: 8,
|
|
250508
250602
|
width: 1024,
|
|
250509
250603
|
height: 1024,
|
|
@@ -250514,16 +250608,161 @@ var init_image_generate = __esm({
|
|
|
250514
250608
|
label: "FLUX.2 Klein",
|
|
250515
250609
|
backend: "ollama",
|
|
250516
250610
|
install: "ollama pull x/flux2-klein",
|
|
250611
|
+
category: "Modern deployable",
|
|
250612
|
+
sizeClass: "4B compact FLUX-family",
|
|
250613
|
+
quality: "Modern FLUX-family quality in a smaller package; useful when full FLUX.1 is too heavy.",
|
|
250614
|
+
minVramGB: 12,
|
|
250615
|
+
recommendedVramGB: 16,
|
|
250616
|
+
deployment: "Ollama model path for practical local experimentation.",
|
|
250517
250617
|
steps: 8,
|
|
250518
250618
|
width: 1024,
|
|
250519
250619
|
height: 1024,
|
|
250520
250620
|
note: "Compact FLUX-family Ollama path for interactive local generation."
|
|
250521
250621
|
},
|
|
250622
|
+
{
|
|
250623
|
+
id: "black-forest-labs/FLUX.1-dev",
|
|
250624
|
+
label: "FLUX.1 dev",
|
|
250625
|
+
backend: "diffusers",
|
|
250626
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model black-forest-labs/FLUX.1-dev --steps 28 --guidance 3.5 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250627
|
+
category: "Primary hyper-realistic baseline",
|
|
250628
|
+
sizeClass: "12B rectified-flow transformer",
|
|
250629
|
+
quality: "Top-tier open-weight photorealism, prompt adherence, texture detail, composition, and typography.",
|
|
250630
|
+
minVramGB: 24,
|
|
250631
|
+
recommendedVramGB: 48,
|
|
250632
|
+
deployment: "Heavy. Best with Diffusers CPU offload, FP8/quantized variants, ComfyUI, multi-GPU, or cloud GPU workers.",
|
|
250633
|
+
steps: 28,
|
|
250634
|
+
guidance: 3.5,
|
|
250635
|
+
width: 1024,
|
|
250636
|
+
height: 1024,
|
|
250637
|
+
note: "Primary serious-generation baseline for maximum photorealism."
|
|
250638
|
+
},
|
|
250639
|
+
{
|
|
250640
|
+
id: "stabilityai/stable-diffusion-3.5-large",
|
|
250641
|
+
label: "Stable Diffusion 3.5 Large",
|
|
250642
|
+
backend: "diffusers",
|
|
250643
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model stabilityai/stable-diffusion-3.5-large --steps 28 --guidance 4.5 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250644
|
+
category: "Primary hyper-realistic baseline",
|
|
250645
|
+
sizeClass: "8B MMDiT",
|
|
250646
|
+
quality: "Serious open Stable Diffusion ecosystem baseline with strong realism, complex prompt understanding, typography, and controllability.",
|
|
250647
|
+
minVramGB: 24,
|
|
250648
|
+
recommendedVramGB: 40,
|
|
250649
|
+
deployment: "Best local candidate for SD/LoRA/ControlNet-style workflows; use offload or quantization below high-VRAM GPUs.",
|
|
250650
|
+
steps: 28,
|
|
250651
|
+
guidance: 4.5,
|
|
250652
|
+
width: 1024,
|
|
250653
|
+
height: 1024,
|
|
250654
|
+
note: "Primary serious-generation baseline for the Stable Diffusion ecosystem."
|
|
250655
|
+
},
|
|
250656
|
+
{
|
|
250657
|
+
id: "black-forest-labs/FLUX.1-schnell",
|
|
250658
|
+
label: "FLUX.1 schnell",
|
|
250659
|
+
backend: "diffusers",
|
|
250660
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model black-forest-labs/FLUX.1-schnell --steps 4 --guidance 0 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250661
|
+
category: "Fast large-model iteration",
|
|
250662
|
+
sizeClass: "12B rectified-flow transformer",
|
|
250663
|
+
quality: "FLUX-style output with fewer steps; better for rapid iteration than absolute peak quality.",
|
|
250664
|
+
minVramGB: 16,
|
|
250665
|
+
recommendedVramGB: 24,
|
|
250666
|
+
deployment: "Use for fast prompt iteration; verify current license terms before commercial use.",
|
|
250667
|
+
steps: 4,
|
|
250668
|
+
guidance: 0,
|
|
250669
|
+
width: 1024,
|
|
250670
|
+
height: 1024,
|
|
250671
|
+
note: "Fast FLUX-family iteration path."
|
|
250672
|
+
},
|
|
250673
|
+
{
|
|
250674
|
+
id: "stabilityai/stable-diffusion-3.5-large-turbo",
|
|
250675
|
+
label: "SD3.5 Large Turbo",
|
|
250676
|
+
backend: "diffusers",
|
|
250677
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model stabilityai/stable-diffusion-3.5-large-turbo --steps 4 --guidance 0 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250678
|
+
category: "Fast large-model iteration",
|
|
250679
|
+
sizeClass: "8B distilled MMDiT",
|
|
250680
|
+
quality: "SD3.5-family quality optimized for fewer inference steps; throughput over peak fidelity.",
|
|
250681
|
+
minVramGB: 16,
|
|
250682
|
+
recommendedVramGB: 24,
|
|
250683
|
+
deployment: "Good for interactive SD3.5-family concepting with offload/quantization when needed.",
|
|
250684
|
+
steps: 4,
|
|
250685
|
+
guidance: 0,
|
|
250686
|
+
width: 1024,
|
|
250687
|
+
height: 1024,
|
|
250688
|
+
note: "Fast SD3.5-family iteration path."
|
|
250689
|
+
},
|
|
250690
|
+
{
|
|
250691
|
+
id: "Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers",
|
|
250692
|
+
label: "HunyuanDiT v1.2",
|
|
250693
|
+
backend: "diffusers",
|
|
250694
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers --steps 30 --guidance 7.5 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250695
|
+
category: "Large multilingual diffusion",
|
|
250696
|
+
sizeClass: "Large DiT text-to-image",
|
|
250697
|
+
quality: "Strong bilingual English/Chinese prompt understanding with detailed, realistic multi-resolution output.",
|
|
250698
|
+
minVramGB: 24,
|
|
250699
|
+
recommendedVramGB: 40,
|
|
250700
|
+
deployment: "Significant GPU memory requirements; prefer Diffusers-compatible variants and offload on smaller GPUs.",
|
|
250701
|
+
steps: 30,
|
|
250702
|
+
guidance: 7.5,
|
|
250703
|
+
width: 1024,
|
|
250704
|
+
height: 1024,
|
|
250705
|
+
note: "Large DiT option for bilingual and detailed realism workflows."
|
|
250706
|
+
},
|
|
250707
|
+
{
|
|
250708
|
+
id: "Tongyi-MAI/Z-Image-Turbo",
|
|
250709
|
+
label: "Z-Image-Turbo",
|
|
250710
|
+
backend: "diffusers",
|
|
250711
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model Tongyi-MAI/Z-Image-Turbo --steps 8 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250712
|
+
category: "Modern deployable",
|
|
250713
|
+
sizeClass: "6B image generation model",
|
|
250714
|
+
quality: "Efficient newer large-model quality; useful below full FLUX/SD3.5 hardware budgets.",
|
|
250715
|
+
minVramGB: 16,
|
|
250716
|
+
recommendedVramGB: 24,
|
|
250717
|
+
deployment: "Candidate for high-end consumer GPUs and optimized runtimes.",
|
|
250718
|
+
steps: 8,
|
|
250719
|
+
width: 1024,
|
|
250720
|
+
height: 1024,
|
|
250721
|
+
note: "Efficient modern large image model."
|
|
250722
|
+
},
|
|
250723
|
+
{
|
|
250724
|
+
id: "black-forest-labs/FLUX.2-klein-4B",
|
|
250725
|
+
label: "FLUX.2 Klein 4B",
|
|
250726
|
+
backend: "diffusers",
|
|
250727
|
+
install: 'python .omnius/image-gen/diffusers_text2image.py --model black-forest-labs/FLUX.2-klein-4B --steps 8 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250728
|
+
category: "Modern deployable",
|
|
250729
|
+
sizeClass: "4B compact FLUX-family",
|
|
250730
|
+
quality: "Bridge between practical deployment and modern FLUX-family visual quality.",
|
|
250731
|
+
minVramGB: 12,
|
|
250732
|
+
recommendedVramGB: 16,
|
|
250733
|
+
deployment: "Better fit for consumer GPU experimentation than 8B-12B baselines.",
|
|
250734
|
+
steps: 8,
|
|
250735
|
+
width: 1024,
|
|
250736
|
+
height: 1024,
|
|
250737
|
+
note: "More deployable compact FLUX-family model."
|
|
250738
|
+
},
|
|
250739
|
+
{
|
|
250740
|
+
id: "deepseek-ai/Janus-Pro-7B",
|
|
250741
|
+
label: "Janus-Pro-7B",
|
|
250742
|
+
backend: "diffusers",
|
|
250743
|
+
install: "experimental research model; use a dedicated Janus pipeline/runtime rather than the generic Diffusers text-to-image runner",
|
|
250744
|
+
category: "Experimental multimodal research",
|
|
250745
|
+
sizeClass: "7B multimodal image generation model",
|
|
250746
|
+
quality: "Relevant research model, but not a classic diffusion baseline for production image pipelines.",
|
|
250747
|
+
minVramGB: 16,
|
|
250748
|
+
recommendedVramGB: 24,
|
|
250749
|
+
deployment: "Experimental/non-classic diffusion-adjacent; list for awareness, not a default production path.",
|
|
250750
|
+
steps: 20,
|
|
250751
|
+
width: 1024,
|
|
250752
|
+
height: 1024,
|
|
250753
|
+
note: "Experimental multimodal generation research model."
|
|
250754
|
+
},
|
|
250522
250755
|
{
|
|
250523
250756
|
id: "segmind/tiny-sd",
|
|
250524
250757
|
label: "Segmind Tiny-SD",
|
|
250525
250758
|
backend: "diffusers",
|
|
250526
250759
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model segmind/tiny-sd --prompt "..." --output .omnius/images/out.png',
|
|
250760
|
+
category: "Lightweight smoke test",
|
|
250761
|
+
sizeClass: "Small SD-compatible",
|
|
250762
|
+
quality: "Fast validation model; not a serious photorealism baseline.",
|
|
250763
|
+
minVramGB: 4,
|
|
250764
|
+
recommendedVramGB: 8,
|
|
250765
|
+
deployment: "Use to verify the local Diffusers stack works before pulling large models.",
|
|
250527
250766
|
steps: 20,
|
|
250528
250767
|
guidance: 7,
|
|
250529
250768
|
width: 512,
|
|
@@ -250535,6 +250774,12 @@ var init_image_generate = __esm({
|
|
|
250535
250774
|
label: "BK-SDM Tiny 2M",
|
|
250536
250775
|
backend: "diffusers",
|
|
250537
250776
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model nota-ai/bk-sdm-tiny-2m --prompt "..." --output .omnius/images/out.png',
|
|
250777
|
+
category: "Lightweight smoke test",
|
|
250778
|
+
sizeClass: "Compressed SD-compatible",
|
|
250779
|
+
quality: "Very small and practical; quality is mainly for tests and rough drafts.",
|
|
250780
|
+
minVramGB: 4,
|
|
250781
|
+
recommendedVramGB: 8,
|
|
250782
|
+
deployment: "Low-friction compressed Stable Diffusion-style model.",
|
|
250538
250783
|
steps: 20,
|
|
250539
250784
|
guidance: 7,
|
|
250540
250785
|
width: 512,
|
|
@@ -250546,6 +250791,12 @@ var init_image_generate = __esm({
|
|
|
250546
250791
|
label: "BK-SDM Small 2M",
|
|
250547
250792
|
backend: "diffusers",
|
|
250548
250793
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model nota-ai/bk-sdm-small-2m --prompt "..." --output .omnius/images/out.png',
|
|
250794
|
+
category: "Lightweight smoke test",
|
|
250795
|
+
sizeClass: "Compressed SD-compatible",
|
|
250796
|
+
quality: "Slightly better compressed-SD quality than tiny variants; still not a high-fidelity baseline.",
|
|
250797
|
+
minVramGB: 4,
|
|
250798
|
+
recommendedVramGB: 8,
|
|
250799
|
+
deployment: "Small quality/size tradeoff for weak hardware.",
|
|
250549
250800
|
steps: 20,
|
|
250550
250801
|
guidance: 7,
|
|
250551
250802
|
width: 512,
|
|
@@ -250557,6 +250808,12 @@ var init_image_generate = __esm({
|
|
|
250557
250808
|
label: "LCM DreamShaper v7",
|
|
250558
250809
|
backend: "diffusers",
|
|
250559
250810
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model SimianLuo/LCM_Dreamshaper_v7 --steps 4 --prompt "..." --output .omnius/images/out.png',
|
|
250811
|
+
category: "Fast iteration",
|
|
250812
|
+
sizeClass: "Few-step SD-compatible",
|
|
250813
|
+
quality: "Good for low-latency concepting; below SDXL/SD3.5/FLUX for photoreal detail.",
|
|
250814
|
+
minVramGB: 6,
|
|
250815
|
+
recommendedVramGB: 8,
|
|
250816
|
+
deployment: "Few-step latent-consistency route.",
|
|
250560
250817
|
steps: 4,
|
|
250561
250818
|
guidance: 8,
|
|
250562
250819
|
width: 512,
|
|
@@ -250568,6 +250825,12 @@ var init_image_generate = __esm({
|
|
|
250568
250825
|
label: "SD-Turbo",
|
|
250569
250826
|
backend: "diffusers",
|
|
250570
250827
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model stabilityai/sd-turbo --steps 1 --guidance 0 --prompt "..." --output .omnius/images/out.png',
|
|
250828
|
+
category: "Fast iteration",
|
|
250829
|
+
sizeClass: "One-to-four-step SD",
|
|
250830
|
+
quality: "Fast SD-family output; useful for iteration but lower ceiling than SDXL Turbo and large baselines.",
|
|
250831
|
+
minVramGB: 6,
|
|
250832
|
+
recommendedVramGB: 8,
|
|
250833
|
+
deployment: "Check Stability license for your use case.",
|
|
250571
250834
|
steps: 1,
|
|
250572
250835
|
guidance: 0,
|
|
250573
250836
|
width: 512,
|
|
@@ -250575,10 +250838,16 @@ var init_image_generate = __esm({
|
|
|
250575
250838
|
note: "One-to-four-step Stable Diffusion family model; check Stability license."
|
|
250576
250839
|
},
|
|
250577
250840
|
{
|
|
250578
|
-
id:
|
|
250841
|
+
id: DEFAULT_DIFFUSERS_IMAGE_MODEL,
|
|
250579
250842
|
label: "SDXL-Turbo",
|
|
250580
250843
|
backend: "diffusers",
|
|
250581
250844
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model stabilityai/sdxl-turbo --steps 1 --guidance 0 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250845
|
+
category: "Default local generation",
|
|
250846
|
+
sizeClass: "Few-step SDXL",
|
|
250847
|
+
quality: "Strong fast default for local image generation; not as realistic as FLUX.1 dev or SD3.5 Large, but much more practical.",
|
|
250848
|
+
minVramGB: 8,
|
|
250849
|
+
recommendedVramGB: 12,
|
|
250850
|
+
deployment: "Auto-installed first-run Diffusers default.",
|
|
250582
250851
|
steps: 1,
|
|
250583
250852
|
guidance: 0,
|
|
250584
250853
|
width: 1024,
|
|
@@ -250590,6 +250859,12 @@ var init_image_generate = __esm({
|
|
|
250590
250859
|
label: "Sana Sprint 0.6B",
|
|
250591
250860
|
backend: "diffusers",
|
|
250592
250861
|
install: 'python .omnius/image-gen/diffusers_text2image.py --model Efficient-Large-Model/Sana_Sprint_0.6B_1024px_diffusers --steps 4 --guidance 0 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
250862
|
+
category: "Modern efficient",
|
|
250863
|
+
sizeClass: "0.6B efficient diffusion",
|
|
250864
|
+
quality: "Modern efficient output under smaller compute budgets; below primary large baselines.",
|
|
250865
|
+
minVramGB: 8,
|
|
250866
|
+
recommendedVramGB: 12,
|
|
250867
|
+
deployment: "Efficient Diffusers path for consumer VRAM.",
|
|
250593
250868
|
steps: 4,
|
|
250594
250869
|
guidance: 0,
|
|
250595
250870
|
width: 1024,
|
|
@@ -250601,6 +250876,12 @@ var init_image_generate = __esm({
|
|
|
250601
250876
|
label: "stable-diffusion.cpp local checkpoint",
|
|
250602
250877
|
backend: "sdcpp",
|
|
250603
250878
|
install: 'python .omnius/image-gen/sdcpp_text2image.py --model-path /path/to/model.gguf --prompt "..." --output .omnius/images/out.png',
|
|
250879
|
+
category: "Local checkpoint/GGUF",
|
|
250880
|
+
sizeClass: "Depends on checkpoint",
|
|
250881
|
+
quality: "Quality depends entirely on the local checkpoint or GGUF variant.",
|
|
250882
|
+
minVramGB: 0,
|
|
250883
|
+
recommendedVramGB: 8,
|
|
250884
|
+
deployment: "CPU/GGUF/checkpoint route for custom local workflows.",
|
|
250604
250885
|
steps: 20,
|
|
250605
250886
|
width: 512,
|
|
250606
250887
|
height: 512,
|
|
@@ -250623,6 +250904,21 @@ def _device():
|
|
|
250623
250904
|
return "mps"
|
|
250624
250905
|
return "cpu"
|
|
250625
250906
|
|
|
250907
|
+
def _pipeline_class(model):
|
|
250908
|
+
lowered = model.lower()
|
|
250909
|
+
if "flux" in lowered:
|
|
250910
|
+
from diffusers import FluxPipeline
|
|
250911
|
+
return FluxPipeline
|
|
250912
|
+
if "stable-diffusion-3.5" in lowered or "stable_diffusion_3" in lowered or "sd3" in lowered:
|
|
250913
|
+
from diffusers import StableDiffusion3Pipeline
|
|
250914
|
+
return StableDiffusion3Pipeline
|
|
250915
|
+
from diffusers import AutoPipelineForText2Image
|
|
250916
|
+
return AutoPipelineForText2Image
|
|
250917
|
+
|
|
250918
|
+
def _large_model(model):
|
|
250919
|
+
lowered = model.lower()
|
|
250920
|
+
return any(token in lowered for token in ["flux.1", "flux.2", "stable-diffusion-3.5", "hunyuan", "z-image", "janus"])
|
|
250921
|
+
|
|
250626
250922
|
def main():
|
|
250627
250923
|
parser = argparse.ArgumentParser()
|
|
250628
250924
|
parser.add_argument("--model", required=True)
|
|
@@ -250639,7 +250935,6 @@ def main():
|
|
|
250639
250935
|
|
|
250640
250936
|
t0 = time.perf_counter()
|
|
250641
250937
|
import torch
|
|
250642
|
-
from diffusers import AutoPipelineForText2Image
|
|
250643
250938
|
|
|
250644
250939
|
device = _device() if args.device == "auto" else args.device
|
|
250645
250940
|
dtype = torch.float16 if device == "cuda" else torch.float32
|
|
@@ -250648,17 +250943,25 @@ def main():
|
|
|
250648
250943
|
kwargs["variant"] = args.variant
|
|
250649
250944
|
|
|
250650
250945
|
try:
|
|
250651
|
-
|
|
250946
|
+
pipeline_cls = _pipeline_class(args.model)
|
|
250947
|
+
pipe = pipeline_cls.from_pretrained(args.model, **kwargs)
|
|
250652
250948
|
except Exception:
|
|
250653
250949
|
kwargs.pop("variant", None)
|
|
250654
|
-
|
|
250950
|
+
pipeline_cls = _pipeline_class(args.model)
|
|
250951
|
+
pipe = pipeline_cls.from_pretrained(args.model, **kwargs)
|
|
250655
250952
|
|
|
250656
250953
|
if hasattr(pipe, "enable_attention_slicing"):
|
|
250657
250954
|
try:
|
|
250658
250955
|
pipe.enable_attention_slicing()
|
|
250659
250956
|
except Exception:
|
|
250660
250957
|
pass
|
|
250661
|
-
|
|
250958
|
+
if device == "cuda" and _large_model(args.model) and hasattr(pipe, "enable_model_cpu_offload"):
|
|
250959
|
+
try:
|
|
250960
|
+
pipe.enable_model_cpu_offload()
|
|
250961
|
+
except Exception:
|
|
250962
|
+
pipe = pipe.to(device)
|
|
250963
|
+
else:
|
|
250964
|
+
pipe = pipe.to(device)
|
|
250662
250965
|
|
|
250663
250966
|
generator = None
|
|
250664
250967
|
if args.seed is not None:
|
|
@@ -250739,7 +251042,7 @@ if __name__ == "__main__":
|
|
|
250739
251042
|
`;
|
|
250740
251043
|
ImageGenerateTool = class {
|
|
250741
251044
|
name = "generate_image";
|
|
250742
|
-
description = "Generate an image from a text prompt using a local image-generation backend. Supports Ollama image models (x/z-image-turbo, x/flux2-klein), Python Diffusers models (
|
|
251045
|
+
description = "Generate an image from a text prompt using a local image-generation backend. Supports Ollama image models (x/z-image-turbo, x/flux2-klein), Python Diffusers models (SDXL Turbo default, FLUX.1 dev, SD3.5 Large, Tiny-SD, LCM, Sana Sprint), and stable-diffusion.cpp local checkpoints/GGUF. Saves a PNG under .omnius/images and returns the file path.";
|
|
250743
251046
|
parameters = {
|
|
250744
251047
|
type: "object",
|
|
250745
251048
|
properties: {
|
|
@@ -250838,11 +251141,11 @@ if __name__ == "__main__":
|
|
|
250838
251141
|
let backend = inferImageGenerationBackend(requestedModel, requestedBackend);
|
|
250839
251142
|
let model = requestedModel;
|
|
250840
251143
|
if (backend === "auto") {
|
|
250841
|
-
|
|
250842
|
-
|
|
251144
|
+
backend = "diffusers";
|
|
251145
|
+
model = DEFAULT_DIFFUSERS_IMAGE_MODEL;
|
|
250843
251146
|
}
|
|
250844
251147
|
if (!model) {
|
|
250845
|
-
model = backend === "diffusers" ?
|
|
251148
|
+
model = backend === "diffusers" ? DEFAULT_DIFFUSERS_IMAGE_MODEL : DEFAULT_OLLAMA_IMAGE_MODEL;
|
|
250846
251149
|
}
|
|
250847
251150
|
if (backend === "ollama") {
|
|
250848
251151
|
return await this.generateWithOllama({ prompt, model, width, height, steps, start: start2 });
|
|
@@ -250934,7 +251237,23 @@ ${errText.slice(0, 800)}`,
|
|
|
250934
251237
|
const runner = await ensureRunner(this.cwd, "diffusers");
|
|
250935
251238
|
await mkdir11(join36(this.cwd, ".omnius", "images"), { recursive: true });
|
|
250936
251239
|
const filepath = outputPath(this.cwd);
|
|
250937
|
-
|
|
251240
|
+
let python;
|
|
251241
|
+
try {
|
|
251242
|
+
python = await ensurePythonFor(this.cwd, "diffusers", typeof args.python === "string" ? args.python : void 0);
|
|
251243
|
+
} catch (err) {
|
|
251244
|
+
const plan = imageGenerationSetupPlan("diffusers", this.cwd, args.model);
|
|
251245
|
+
return {
|
|
251246
|
+
success: false,
|
|
251247
|
+
output: [
|
|
251248
|
+
`Diffusers setup failed before image generation.`,
|
|
251249
|
+
err instanceof Error ? err.message : String(err),
|
|
251250
|
+
"",
|
|
251251
|
+
"Setup path:",
|
|
251252
|
+
...plan.commands.map((cmd) => ` ${cmd}`)
|
|
251253
|
+
].filter(Boolean).join("\n"),
|
|
251254
|
+
durationMs: performance.now() - args.start
|
|
251255
|
+
};
|
|
251256
|
+
}
|
|
250938
251257
|
const argv = [
|
|
250939
251258
|
runner,
|
|
250940
251259
|
"--model",
|
|
@@ -250954,7 +251273,7 @@ ${errText.slice(0, 800)}`,
|
|
|
250954
251273
|
];
|
|
250955
251274
|
if (args.seed !== void 0)
|
|
250956
251275
|
argv.push("--seed", String(args.seed));
|
|
250957
|
-
const result = await runProcess2(command, argv, { cwd: this.cwd, timeoutMs: 9e5 });
|
|
251276
|
+
const result = await runProcess2(python.command, argv, { cwd: this.cwd, timeoutMs: 9e5, env: python.env });
|
|
250958
251277
|
if (result.code !== 0 || !existsSync23(filepath)) {
|
|
250959
251278
|
const plan = imageGenerationSetupPlan("diffusers", this.cwd, args.model);
|
|
250960
251279
|
return {
|
|
@@ -251008,7 +251327,23 @@ ${errText.slice(0, 800)}`,
|
|
|
251008
251327
|
const runner = await ensureRunner(this.cwd, "sdcpp");
|
|
251009
251328
|
await mkdir11(join36(this.cwd, ".omnius", "images"), { recursive: true });
|
|
251010
251329
|
const filepath = outputPath(this.cwd);
|
|
251011
|
-
|
|
251330
|
+
let python;
|
|
251331
|
+
try {
|
|
251332
|
+
python = await ensurePythonFor(this.cwd, "sdcpp", typeof args.python === "string" ? args.python : void 0);
|
|
251333
|
+
} catch (err) {
|
|
251334
|
+
const plan = imageGenerationSetupPlan("sdcpp", this.cwd, args.model);
|
|
251335
|
+
return {
|
|
251336
|
+
success: false,
|
|
251337
|
+
output: [
|
|
251338
|
+
`stable-diffusion.cpp setup failed before image generation.`,
|
|
251339
|
+
err instanceof Error ? err.message : String(err),
|
|
251340
|
+
"",
|
|
251341
|
+
"Setup path:",
|
|
251342
|
+
...plan.commands.map((cmd) => ` ${cmd}`)
|
|
251343
|
+
].filter(Boolean).join("\n"),
|
|
251344
|
+
durationMs: performance.now() - args.start
|
|
251345
|
+
};
|
|
251346
|
+
}
|
|
251012
251347
|
const argv = [
|
|
251013
251348
|
runner,
|
|
251014
251349
|
"--model-path",
|
|
@@ -251026,7 +251361,7 @@ ${errText.slice(0, 800)}`,
|
|
|
251026
251361
|
];
|
|
251027
251362
|
if (args.seed !== void 0)
|
|
251028
251363
|
argv.push("--seed", String(args.seed));
|
|
251029
|
-
const result = await runProcess2(command, argv, { cwd: this.cwd, timeoutMs: 9e5 });
|
|
251364
|
+
const result = await runProcess2(python.command, argv, { cwd: this.cwd, timeoutMs: 9e5, env: python.env });
|
|
251030
251365
|
if (result.code !== 0 || !existsSync23(filepath)) {
|
|
251031
251366
|
const plan = imageGenerationSetupPlan("sdcpp", this.cwd, args.model);
|
|
251032
251367
|
return {
|
|
@@ -512881,6 +513216,8 @@ __export(dist_exports, {
|
|
|
512881
513216
|
CreateToolTool: () => CreateToolTool,
|
|
512882
513217
|
CronAgentTool: () => CronAgentTool,
|
|
512883
513218
|
CustomTool: () => CustomTool,
|
|
513219
|
+
DEFAULT_DIFFUSERS_IMAGE_MODEL: () => DEFAULT_DIFFUSERS_IMAGE_MODEL,
|
|
513220
|
+
DEFAULT_OLLAMA_IMAGE_MODEL: () => DEFAULT_OLLAMA_IMAGE_MODEL,
|
|
512884
513221
|
DESKTOP_DEPS: () => DESKTOP_DEPS,
|
|
512885
513222
|
DebateTool: () => DebateTool,
|
|
512886
513223
|
DesktopClickTool: () => DesktopClickTool,
|
|
@@ -513002,6 +513339,7 @@ __export(dist_exports, {
|
|
|
513002
513339
|
deleteTodos: () => deleteTodos,
|
|
513003
513340
|
detectElevationMethod: () => detectElevationMethod,
|
|
513004
513341
|
detectSearchProvider: () => detectSearchProvider,
|
|
513342
|
+
diffusersVenvDir: () => diffusersVenvDir,
|
|
513005
513343
|
discoverPlugins: () => discoverPlugins,
|
|
513006
513344
|
discoverSkills: () => discoverSkills,
|
|
513007
513345
|
emitIndexed: () => emitIndexed,
|
|
@@ -513034,6 +513372,7 @@ __export(dist_exports, {
|
|
|
513034
513372
|
getWorkingNotesSummary: () => getWorkingNotesSummary,
|
|
513035
513373
|
getWorktreeSession: () => getWorktreeSession,
|
|
513036
513374
|
hashGeneratedArtifactContent: () => hashGeneratedArtifactContent,
|
|
513375
|
+
imageGenerationDir: () => imageGenerationDir,
|
|
513037
513376
|
imageGenerationSetupPlan: () => imageGenerationSetupPlan,
|
|
513038
513377
|
inferImageGenerationBackend: () => inferImageGenerationBackend,
|
|
513039
513378
|
isFortemiAvailable: () => isFortemiAvailable,
|
|
@@ -513084,6 +513423,7 @@ __export(dist_exports, {
|
|
|
513084
513423
|
saveCustomToolDefinition: () => saveCustomToolDefinition,
|
|
513085
513424
|
saveMcpServerToConfig: () => saveMcpServerToConfig,
|
|
513086
513425
|
savePacket: () => savePacket,
|
|
513426
|
+
sdcppVenvDir: () => sdcppVenvDir,
|
|
513087
513427
|
serializeMap: () => serializeMap,
|
|
513088
513428
|
setChangeLogSession: () => setChangeLogSession,
|
|
513089
513429
|
setSudoPassword: () => setSudoPassword,
|
|
@@ -526549,6 +526889,14 @@ var init_app_state = __esm({
|
|
|
526549
526889
|
});
|
|
526550
526890
|
|
|
526551
526891
|
// packages/orchestrator/dist/streaming-executor.js
|
|
526892
|
+
function stableValueKey(value2) {
|
|
526893
|
+
if (value2 === null || typeof value2 !== "object")
|
|
526894
|
+
return JSON.stringify(value2);
|
|
526895
|
+
if (Array.isArray(value2))
|
|
526896
|
+
return `[${value2.map(stableValueKey).join(",")}]`;
|
|
526897
|
+
const record = value2;
|
|
526898
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableValueKey(record[key])}`).join(",")}}`;
|
|
526899
|
+
}
|
|
526552
526900
|
var StreamingToolExecutor;
|
|
526553
526901
|
var init_streaming_executor = __esm({
|
|
526554
526902
|
"packages/orchestrator/dist/streaming-executor.js"() {
|
|
@@ -526700,6 +527048,62 @@ var init_streaming_executor = __esm({
|
|
|
526700
527048
|
return true;
|
|
526701
527049
|
return false;
|
|
526702
527050
|
}
|
|
527051
|
+
entryFingerprint(entry) {
|
|
527052
|
+
return `${entry.name}:${stableValueKey(entry.args)}`;
|
|
527053
|
+
}
|
|
527054
|
+
findPriorEquivalent(entry) {
|
|
527055
|
+
const entryIdx = this.insertionOrder.indexOf(entry.id);
|
|
527056
|
+
if (entryIdx <= 0 || !entry.finalized)
|
|
527057
|
+
return null;
|
|
527058
|
+
const fp = this.entryFingerprint(entry);
|
|
527059
|
+
for (let i2 = 0; i2 < entryIdx; i2++) {
|
|
527060
|
+
const prior = this.tools.get(this.insertionOrder[i2]);
|
|
527061
|
+
if (!prior || !prior.finalized)
|
|
527062
|
+
continue;
|
|
527063
|
+
if (this.entryFingerprint(prior) === fp)
|
|
527064
|
+
return prior;
|
|
527065
|
+
}
|
|
527066
|
+
return null;
|
|
527067
|
+
}
|
|
527068
|
+
cloneDuplicateResult(prior) {
|
|
527069
|
+
if (!prior.result)
|
|
527070
|
+
return null;
|
|
527071
|
+
const prefix = `[DUPLICATE STREAM TOOL CALL — reused result from ${prior.id}]
|
|
527072
|
+
`;
|
|
527073
|
+
return {
|
|
527074
|
+
success: prior.result.success,
|
|
527075
|
+
output: prior.result.output ? `${prefix}${prior.result.output}` : prior.result.output,
|
|
527076
|
+
error: prior.result.error
|
|
527077
|
+
};
|
|
527078
|
+
}
|
|
527079
|
+
mirrorPriorEquivalent(entry) {
|
|
527080
|
+
const prior = this.findPriorEquivalent(entry);
|
|
527081
|
+
if (!prior)
|
|
527082
|
+
return false;
|
|
527083
|
+
if ((prior.state === "completed" || prior.state === "failed" || prior.state === "yielded") && prior.result) {
|
|
527084
|
+
entry.state = prior.result.success ? "completed" : "failed";
|
|
527085
|
+
entry.result = this.cloneDuplicateResult(prior) ?? prior.result;
|
|
527086
|
+
entry.startedAt = prior.startedAt;
|
|
527087
|
+
entry.completedAt = prior.completedAt ?? Date.now();
|
|
527088
|
+
return true;
|
|
527089
|
+
}
|
|
527090
|
+
if (prior.state === "executing" && prior.promise) {
|
|
527091
|
+
entry.state = "executing";
|
|
527092
|
+
entry.startedAt = prior.startedAt ?? Date.now();
|
|
527093
|
+
entry.promise = prior.promise.then(() => {
|
|
527094
|
+
entry.result = this.cloneDuplicateResult(prior) ?? {
|
|
527095
|
+
success: false,
|
|
527096
|
+
output: "",
|
|
527097
|
+
error: "Duplicate streaming tool call could not reuse prior result"
|
|
527098
|
+
};
|
|
527099
|
+
entry.state = entry.result.success ? "completed" : "failed";
|
|
527100
|
+
entry.completedAt = Date.now();
|
|
527101
|
+
this.processQueue();
|
|
527102
|
+
});
|
|
527103
|
+
return true;
|
|
527104
|
+
}
|
|
527105
|
+
return false;
|
|
527106
|
+
}
|
|
526703
527107
|
/**
|
|
526704
527108
|
* Process the queue in insertion order.
|
|
526705
527109
|
* Starts tools that can execute, stops at first exclusive tool that must wait.
|
|
@@ -526709,6 +527113,8 @@ var init_streaming_executor = __esm({
|
|
|
526709
527113
|
const entry = this.tools.get(id);
|
|
526710
527114
|
if (!entry || entry.state !== "queued")
|
|
526711
527115
|
continue;
|
|
527116
|
+
if (this.mirrorPriorEquivalent(entry))
|
|
527117
|
+
continue;
|
|
526712
527118
|
if (this.canExecute(entry)) {
|
|
526713
527119
|
this.startExecution(entry);
|
|
526714
527120
|
} else if (!entry.concurrencySafe) {
|
|
@@ -535466,6 +535872,7 @@ ${sr.result.output}`;
|
|
|
535466
535872
|
this.emit({
|
|
535467
535873
|
type: "assistant_text",
|
|
535468
535874
|
content: summary,
|
|
535875
|
+
source: "task_complete_summary",
|
|
535469
535876
|
turn,
|
|
535470
535877
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535471
535878
|
});
|
|
@@ -535506,6 +535913,7 @@ ${sr.result.output}`;
|
|
|
535506
535913
|
this.emit({
|
|
535507
535914
|
type: "assistant_text",
|
|
535508
535915
|
content: summary,
|
|
535916
|
+
source: "task_complete_summary",
|
|
535509
535917
|
turn,
|
|
535510
535918
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535511
535919
|
});
|
|
@@ -535581,6 +535989,7 @@ ${sr.result.output}`;
|
|
|
535581
535989
|
this.emit({
|
|
535582
535990
|
type: "assistant_text",
|
|
535583
535991
|
content: summary,
|
|
535992
|
+
source: "task_complete_summary",
|
|
535584
535993
|
turn,
|
|
535585
535994
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
535586
535995
|
});
|
|
@@ -536306,6 +536715,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
536306
536715
|
this.emit({
|
|
536307
536716
|
type: "assistant_text",
|
|
536308
536717
|
content: summary,
|
|
536718
|
+
source: "task_complete_summary",
|
|
536309
536719
|
turn,
|
|
536310
536720
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
536311
536721
|
});
|
|
@@ -540152,6 +540562,7 @@ ${description}`
|
|
|
540152
540562
|
this.emit({
|
|
540153
540563
|
type: "assistant_text",
|
|
540154
540564
|
content: cleanContent,
|
|
540565
|
+
source: "model_visible_text",
|
|
540155
540566
|
turn,
|
|
540156
540567
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
540157
540568
|
});
|
|
@@ -550151,7 +550562,7 @@ var init_command_registry = __esm({
|
|
|
550151
550562
|
["/image <prompt>", "Generate an image from a prompt and show an ASCII preview"],
|
|
550152
550563
|
["/image --model <model> <prompt>", "Generate with an explicit image model"],
|
|
550153
550564
|
["/image setup <ollama|diffusers|sdcpp>", "Show setup commands for an image-generation backend"],
|
|
550154
|
-
["/image
|
|
550565
|
+
["/image list", "List image models by category, quality, size, and hardware fit"],
|
|
550155
550566
|
["/call", "Start voice call session (cloudflared tunnel + ASR/TTS)"],
|
|
550156
550567
|
["/hangup", "End active call session"],
|
|
550157
550568
|
["/queue <prompt>", "Queue a prompt for the next turn without interrupting the current run"],
|
|
@@ -572210,14 +572621,16 @@ ${preview.ascii}`;
|
|
|
572210
572621
|
function extractSavedImagePath(text, repoRoot) {
|
|
572211
572622
|
const patterns = [
|
|
572212
572623
|
/Image generated:\s*([^\n\r]+)/i,
|
|
572624
|
+
/Screenshot saved:\s*([^\n\r]+)/i,
|
|
572625
|
+
/Screenshot:\s*([^\n\r]+)/i,
|
|
572213
572626
|
/Saved to:\s*([^\n\r]+)/i,
|
|
572214
572627
|
/Image attached:\s*([^\n\r]+)/i,
|
|
572215
|
-
/image saved at\s+([^\n\r
|
|
572628
|
+
/image saved at\s+([^\n\r]+)/i
|
|
572216
572629
|
];
|
|
572217
572630
|
for (const pattern of patterns) {
|
|
572218
572631
|
const match = text.match(pattern);
|
|
572219
572632
|
if (!match?.[1]) continue;
|
|
572220
|
-
const raw = match[1].trim().replace(/^["']|["']$/g, "");
|
|
572633
|
+
const raw = match[1].trim().replace(/\s+\([^)]+\)\s*$/g, "").replace(/^["']|["']$/g, "");
|
|
572221
572634
|
const candidate = raw.startsWith("/") ? raw : resolve37(repoRoot, raw);
|
|
572222
572635
|
if (existsSync93(candidate)) return candidate;
|
|
572223
572636
|
}
|
|
@@ -582555,18 +582968,123 @@ function parseImageNumber(value2) {
|
|
|
582555
582968
|
const n2 = Number(value2);
|
|
582556
582969
|
return Number.isFinite(n2) ? n2 : void 0;
|
|
582557
582970
|
}
|
|
582971
|
+
function rateImagePresetForHardware(preset, specs) {
|
|
582972
|
+
const min = preset.minVramGB ?? (preset.backend === "sdcpp" ? 0 : 8);
|
|
582973
|
+
const recommended = preset.recommendedVramGB ?? Math.max(min, 12);
|
|
582974
|
+
const vram = specs.gpuVramGB;
|
|
582975
|
+
const ram = Math.max(specs.availableRamGB, specs.totalRamGB * 0.65);
|
|
582976
|
+
if (preset.id === "deepseek-ai/Janus-Pro-7B") {
|
|
582977
|
+
const base3 = vram >= recommended ? 65 : vram >= min ? 50 : 25;
|
|
582978
|
+
return {
|
|
582979
|
+
score: base3,
|
|
582980
|
+
label: base3 >= 60 ? "experimental" : "not turnkey",
|
|
582981
|
+
note: "Experimental multimodal model; use a dedicated Janus runtime, not the generic Diffusers runner."
|
|
582982
|
+
};
|
|
582983
|
+
}
|
|
582984
|
+
if (min <= 0) {
|
|
582985
|
+
const score2 = vram >= recommended ? 85 : vram > 0 ? 70 : ram >= 32 ? 45 : 25;
|
|
582986
|
+
return {
|
|
582987
|
+
score: score2,
|
|
582988
|
+
label: score2 >= 80 ? "comfortable" : score2 >= 60 ? "workable" : "checkpoint-dependent",
|
|
582989
|
+
note: vram > 0 ? "Fit depends on the local checkpoint/GGUF size and runtime flags." : "CPU/GGUF path is possible but will be slow; choose small quantized checkpoints."
|
|
582990
|
+
};
|
|
582991
|
+
}
|
|
582992
|
+
let score;
|
|
582993
|
+
let label;
|
|
582994
|
+
let note;
|
|
582995
|
+
if (vram >= recommended) {
|
|
582996
|
+
score = Math.min(100, Math.round(90 + Math.min(10, (vram - recommended) / Math.max(1, recommended) * 10)));
|
|
582997
|
+
label = "excellent";
|
|
582998
|
+
note = `Runs well on ${vram.toFixed(0)}GB VRAM; enough headroom for ${preset.sizeClass ?? "this model"}.`;
|
|
582999
|
+
} else if (vram >= min) {
|
|
583000
|
+
score = Math.round(70 + (vram - min) / Math.max(1, recommended - min) * 18);
|
|
583001
|
+
label = "comfortable";
|
|
583002
|
+
note = `Fits the stated ${min.toFixed(0)}GB minimum; expect lower batching/headroom than the ${recommended.toFixed(0)}GB target.`;
|
|
583003
|
+
} else if (vram > 0 && ram >= recommended * 1.5) {
|
|
583004
|
+
score = 52;
|
|
583005
|
+
label = "offload";
|
|
583006
|
+
note = `Below ${min.toFixed(0)}GB VRAM; may work with CPU offload or quantization, but latency and reliability will suffer.`;
|
|
583007
|
+
} else if (ram >= recommended * 2) {
|
|
583008
|
+
score = 35;
|
|
583009
|
+
label = "cloud/quant";
|
|
583010
|
+
note = "System RAM is large enough for experiments, but VRAM is below target; prefer quantized runtimes or cloud GPU.";
|
|
583011
|
+
} else {
|
|
583012
|
+
score = 18;
|
|
583013
|
+
label = "too heavy";
|
|
583014
|
+
note = `Needs roughly ${min.toFixed(0)}GB VRAM minimum and ${recommended.toFixed(0)}GB recommended.`;
|
|
583015
|
+
}
|
|
583016
|
+
return { score, label, note };
|
|
583017
|
+
}
|
|
583018
|
+
function imageFitIcon(score) {
|
|
583019
|
+
if (score >= 85) return c3.green("✔");
|
|
583020
|
+
if (score >= 60) return c3.green("◐");
|
|
583021
|
+
if (score >= 40) return c3.yellow("△");
|
|
583022
|
+
return c3.red("✖");
|
|
583023
|
+
}
|
|
583024
|
+
function wrapImageListText(text, width = 94) {
|
|
583025
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
583026
|
+
const lines = [];
|
|
583027
|
+
let line = "";
|
|
583028
|
+
for (const word2 of words) {
|
|
583029
|
+
if (!line) line = word2;
|
|
583030
|
+
else if (line.length + 1 + word2.length <= width) line += ` ${word2}`;
|
|
583031
|
+
else {
|
|
583032
|
+
lines.push(line);
|
|
583033
|
+
line = word2;
|
|
583034
|
+
}
|
|
583035
|
+
}
|
|
583036
|
+
if (line) lines.push(line);
|
|
583037
|
+
return lines.length > 0 ? lines : [""];
|
|
583038
|
+
}
|
|
583039
|
+
function renderImagePresetDetail(prefix, text) {
|
|
583040
|
+
const [first2, ...rest] = wrapImageListText(text, 92);
|
|
583041
|
+
renderInfo(`${prefix}${first2}`);
|
|
583042
|
+
for (const line of rest) renderInfo(`${" ".repeat(prefix.length)}${line}`);
|
|
583043
|
+
}
|
|
583044
|
+
function renderImageModelList() {
|
|
583045
|
+
const specs = detectSystemSpecs();
|
|
583046
|
+
const hardware = `${specs.totalRamGB.toFixed(0)}GB RAM` + (specs.gpuVramGB > 0 ? ` + ${specs.gpuVramGB.toFixed(0)}GB VRAM (${specs.gpuName || "NVIDIA GPU"})` : " + no NVIDIA VRAM detected");
|
|
583047
|
+
renderInfo(`Image models for this hardware: ${hardware}`);
|
|
583048
|
+
renderInfo("Fit legend: 85+ excellent, 60+ comfortable, 40+ offload/quantized, below 40 heavy/cloud.");
|
|
583049
|
+
renderInfo("Primary hyper-realistic baselines: FLUX.1 dev and Stable Diffusion 3.5 Large.");
|
|
583050
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
583051
|
+
for (const preset of IMAGE_GENERATION_MODEL_PRESETS) {
|
|
583052
|
+
const category = preset.category ?? "Other";
|
|
583053
|
+
const list = byCategory.get(category) ?? [];
|
|
583054
|
+
list.push(preset);
|
|
583055
|
+
byCategory.set(category, list);
|
|
583056
|
+
}
|
|
583057
|
+
for (const [category, presets] of byCategory) {
|
|
583058
|
+
renderInfo("");
|
|
583059
|
+
renderInfo(c3.bold(category));
|
|
583060
|
+
for (const preset of presets) {
|
|
583061
|
+
const fit2 = rateImagePresetForHardware(preset, specs);
|
|
583062
|
+
const primary = category === "Primary hyper-realistic baseline" ? c3.cyan(" ★") : "";
|
|
583063
|
+
renderInfo(`${imageFitIcon(fit2.score)} ${String(fit2.score).padStart(3)}/100 ${c3.bold(preset.label)}${primary}`);
|
|
583064
|
+
renderInfo(` id: ${preset.id}`);
|
|
583065
|
+
renderInfo(` type: ${preset.backend} · ${preset.sizeClass ?? "unknown size"} · ${fit2.label}`);
|
|
583066
|
+
renderImagePresetDetail(" quality: ", preset.quality ?? preset.note);
|
|
583067
|
+
renderImagePresetDetail(" fit: ", fit2.note);
|
|
583068
|
+
if (preset.deployment) renderImagePresetDetail(" deploy: ", preset.deployment);
|
|
583069
|
+
}
|
|
583070
|
+
}
|
|
583071
|
+
}
|
|
582558
583072
|
async function showImageModelsMenu(ctx3, hasLocal) {
|
|
582559
583073
|
const settings = resolveSettings(ctx3.repoRoot);
|
|
583074
|
+
const specs = detectSystemSpecs();
|
|
582560
583075
|
const items = [
|
|
582561
583076
|
{ key: "setup:ollama", label: "Setup Ollama", detail: "Pull x/z-image-turbo or x/flux2-klein" },
|
|
582562
|
-
{ key: "setup:diffusers", label: "Setup Diffusers", detail: "
|
|
583077
|
+
{ key: "setup:diffusers", label: "Setup Diffusers", detail: "Auto-installs SDXL Turbo under .omnius/image-gen/.venv" },
|
|
582563
583078
|
{ key: "setup:sdcpp", label: "Setup stable-diffusion.cpp", detail: "CPU/GGUF/checkpoint route" },
|
|
582564
583079
|
{ key: "hdr:models", label: selectColors.dim("─── Models ───") },
|
|
582565
|
-
...IMAGE_GENERATION_MODEL_PRESETS.map((preset) =>
|
|
582566
|
-
|
|
582567
|
-
|
|
582568
|
-
|
|
582569
|
-
|
|
583080
|
+
...IMAGE_GENERATION_MODEL_PRESETS.map((preset) => {
|
|
583081
|
+
const fit2 = rateImagePresetForHardware(preset, specs);
|
|
583082
|
+
return {
|
|
583083
|
+
key: `model:${preset.id}`,
|
|
583084
|
+
label: preset.label,
|
|
583085
|
+
detail: `${fit2.score}/100 ${fit2.label} · ${preset.category ?? preset.backend} · ${preset.sizeClass ?? preset.id}`
|
|
583086
|
+
};
|
|
583087
|
+
})
|
|
582570
583088
|
];
|
|
582571
583089
|
const result = await tuiSelect({
|
|
582572
583090
|
items,
|
|
@@ -582602,10 +583120,8 @@ async function handleImageCommand(ctx3, arg, hasLocal) {
|
|
|
582602
583120
|
await showImageModelsMenu(ctx3, hasLocal);
|
|
582603
583121
|
return "handled";
|
|
582604
583122
|
}
|
|
582605
|
-
if (parsed.subcommand === "models") {
|
|
582606
|
-
|
|
582607
|
-
renderInfo(`${preset.id} [${preset.backend}] ${preset.note}`);
|
|
582608
|
-
}
|
|
583123
|
+
if (parsed.subcommand === "models" || parsed.subcommand === "list") {
|
|
583124
|
+
renderImageModelList();
|
|
582609
583125
|
return "handled";
|
|
582610
583126
|
}
|
|
582611
583127
|
if (parsed.subcommand === "setup") {
|
|
@@ -582617,7 +583133,7 @@ async function handleImageCommand(ctx3, arg, hasLocal) {
|
|
|
582617
583133
|
for (const note of plan.notes) renderInfo(`- ${note}`);
|
|
582618
583134
|
return "handled";
|
|
582619
583135
|
}
|
|
582620
|
-
const model = String(parsed.flags["model"] ?? settings.imageModel ??
|
|
583136
|
+
const model = String(parsed.flags["model"] ?? settings.imageModel ?? DEFAULT_DIFFUSERS_IMAGE_MODEL);
|
|
582621
583137
|
const backend = String(parsed.flags["backend"] ?? settings.imageBackend ?? inferImageGenerationBackend(model, void 0));
|
|
582622
583138
|
const tool = new ImageGenerateTool(ctx3.repoRoot, ctx3.config.backendUrl);
|
|
582623
583139
|
const prompt = parsed.prompt;
|
|
@@ -593406,6 +593922,13 @@ function sanitizeTelegramProgressText(text, maxLength) {
|
|
|
593406
593922
|
function compactTelegramVisibleText(text) {
|
|
593407
593923
|
return stripTelegramHiddenThinking(text).replace(/\s+/g, " ").trim();
|
|
593408
593924
|
}
|
|
593925
|
+
function stableTelegramValueKey(value2) {
|
|
593926
|
+
if (value2 === void 0) return "undefined";
|
|
593927
|
+
if (value2 === null || typeof value2 !== "object") return JSON.stringify(value2) ?? String(value2);
|
|
593928
|
+
if (Array.isArray(value2)) return `[${value2.map(stableTelegramValueKey).join(",")}]`;
|
|
593929
|
+
const record = value2;
|
|
593930
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableTelegramValueKey(record[key])}`).join(",")}}`;
|
|
593931
|
+
}
|
|
593409
593932
|
function isTelegramPotentialNoReplyPrefix(text) {
|
|
593410
593933
|
const lower = compactTelegramVisibleText(text).toLowerCase();
|
|
593411
593934
|
return Boolean(lower) && "no_reply".startsWith(lower);
|
|
@@ -593436,7 +593959,39 @@ function cleanTelegramVisibleReply(text, options2 = {}) {
|
|
|
593436
593959
|
if (!clean3) return "";
|
|
593437
593960
|
if (options2.suppressPotentialNoReplyPrefix && isTelegramPotentialNoReplyPrefix(clean3)) return "";
|
|
593438
593961
|
if (isTelegramInternalStatusText(clean3)) return "";
|
|
593439
|
-
return clean3;
|
|
593962
|
+
return dedupeTelegramVisibleReply(clean3);
|
|
593963
|
+
}
|
|
593964
|
+
function dedupeTelegramVisibleReply(text) {
|
|
593965
|
+
const paragraphs = text.split(/\n{2,}/);
|
|
593966
|
+
const seenParagraphs = /* @__PURE__ */ new Set();
|
|
593967
|
+
const collapsedParagraphs = [];
|
|
593968
|
+
for (const paragraph of paragraphs) {
|
|
593969
|
+
const clean3 = paragraph.trim();
|
|
593970
|
+
if (!clean3) continue;
|
|
593971
|
+
const key = compactTelegramVisibleText(clean3).toLowerCase();
|
|
593972
|
+
if (seenParagraphs.has(key)) continue;
|
|
593973
|
+
seenParagraphs.add(key);
|
|
593974
|
+
collapsedParagraphs.push(clean3);
|
|
593975
|
+
}
|
|
593976
|
+
const paragraphCollapsed = collapsedParagraphs.join("\n\n");
|
|
593977
|
+
const sentenceLike = paragraphCollapsed.match(/[^.!?]+[.!?]+|[^.!?]+$/g);
|
|
593978
|
+
if (!sentenceLike || sentenceLike.length < 3) return paragraphCollapsed;
|
|
593979
|
+
const seenSentences = /* @__PURE__ */ new Set();
|
|
593980
|
+
const out = [];
|
|
593981
|
+
let duplicates = 0;
|
|
593982
|
+
for (const raw of sentenceLike) {
|
|
593983
|
+
const sentence = raw.trim();
|
|
593984
|
+
if (!sentence) continue;
|
|
593985
|
+
const key = sentence.replace(/\s+/g, " ").toLowerCase();
|
|
593986
|
+
if (seenSentences.has(key)) {
|
|
593987
|
+
duplicates++;
|
|
593988
|
+
continue;
|
|
593989
|
+
}
|
|
593990
|
+
seenSentences.add(key);
|
|
593991
|
+
out.push(sentence);
|
|
593992
|
+
}
|
|
593993
|
+
if (duplicates === 0) return paragraphCollapsed;
|
|
593994
|
+
return out.join(" ").trim();
|
|
593440
593995
|
}
|
|
593441
593996
|
function truncateTelegramContext(text, maxLength) {
|
|
593442
593997
|
const trimmed = text.trim();
|
|
@@ -593560,11 +594115,10 @@ function selectTelegramFinalResponse(args) {
|
|
|
593560
594115
|
args.assistantText
|
|
593561
594116
|
].map((candidate) => cleanTelegramVisibleReply(candidate || "")).filter(Boolean);
|
|
593562
594117
|
if (visibleCandidates.length > 0) {
|
|
593563
|
-
return visibleCandidates
|
|
593564
|
-
(best, current) => current.length > best.length ? current : best
|
|
593565
|
-
);
|
|
594118
|
+
return visibleCandidates[0];
|
|
593566
594119
|
}
|
|
593567
|
-
|
|
594120
|
+
void args.summary;
|
|
594121
|
+
return "";
|
|
593568
594122
|
}
|
|
593569
594123
|
function formatTelegramProgressEvent(event) {
|
|
593570
594124
|
if (event.type === "tool_call" && event.toolName === "task_complete") return null;
|
|
@@ -593853,6 +594407,26 @@ function telegramImageMime(media) {
|
|
|
593853
594407
|
if (ext === ".tif" || ext === ".tiff") return "image/tiff";
|
|
593854
594408
|
return "image/jpeg";
|
|
593855
594409
|
}
|
|
594410
|
+
function extractTelegramMentionedUsernames(message2, text) {
|
|
594411
|
+
const usernames = /* @__PURE__ */ new Set();
|
|
594412
|
+
const entities = [
|
|
594413
|
+
...Array.isArray(message2.entities) ? message2.entities : [],
|
|
594414
|
+
...Array.isArray(message2.caption_entities) ? message2.caption_entities : []
|
|
594415
|
+
];
|
|
594416
|
+
for (const entity of entities) {
|
|
594417
|
+
if (!entity || typeof entity !== "object") continue;
|
|
594418
|
+
if (entity.type === "mention") {
|
|
594419
|
+
const offset = Number(entity.offset);
|
|
594420
|
+
const length4 = Number(entity.length);
|
|
594421
|
+
if (!Number.isFinite(offset) || !Number.isFinite(length4) || length4 <= 1) continue;
|
|
594422
|
+
const mention = text.slice(offset, offset + length4).replace(/^@/, "").trim();
|
|
594423
|
+
if (mention) usernames.add(mention);
|
|
594424
|
+
} else if (entity.type === "text_mention" && typeof entity.user?.username === "string") {
|
|
594425
|
+
usernames.add(entity.user.username);
|
|
594426
|
+
}
|
|
594427
|
+
}
|
|
594428
|
+
return [...usernames];
|
|
594429
|
+
}
|
|
593856
594430
|
function normalizeTelegramUpdate(update2) {
|
|
593857
594431
|
const sourceUpdateType = update2.guest_message ? "guest_message" : update2.message ? "message" : null;
|
|
593858
594432
|
if (!sourceUpdateType) return null;
|
|
@@ -593885,6 +594459,9 @@ function normalizeTelegramUpdate(update2) {
|
|
|
593885
594459
|
isDirectMessages: Boolean(message2.chat?.is_direct_messages),
|
|
593886
594460
|
parentChatId: message2.chat?.parent_chat?.id ?? message2.direct_messages_topic?.parent_topic?.id,
|
|
593887
594461
|
replyToMessageId: message2.reply_to_message?.message_id,
|
|
594462
|
+
replyToUsername: message2.reply_to_message?.from?.username ?? message2.reply_to_message?.sender_chat?.username,
|
|
594463
|
+
replyToBot: Boolean(message2.reply_to_message?.from?.is_bot),
|
|
594464
|
+
mentionedUsernames: extractTelegramMentionedUsernames(message2, text),
|
|
593888
594465
|
sourceUpdateType
|
|
593889
594466
|
};
|
|
593890
594467
|
}
|
|
@@ -593943,10 +594520,10 @@ function renderTelegramStart(botUsername, adminId, mode = "auto") {
|
|
|
593943
594520
|
if (adminId) {
|
|
593944
594521
|
process.stdout.write(` ${c3.dim(`Admin: ${adminId} (full memory + tools)`)}
|
|
593945
594522
|
`);
|
|
593946
|
-
process.stdout.write(` ${c3.dim("Public users:
|
|
594523
|
+
process.stdout.write(` ${c3.dim("Public users: scoped memory + web + per-chat creative file/image/audio tools")}
|
|
593947
594524
|
`);
|
|
593948
594525
|
}
|
|
593949
|
-
process.stdout.write(` ${c3.dim("Safety filter: ACTIVE — public channel mode")}
|
|
594526
|
+
process.stdout.write(` ${c3.dim("Safety filter: ACTIVE — public channel mode; creative writes are sandboxed under .omnius/telegram-creative/<chat>")}
|
|
593950
594527
|
`);
|
|
593951
594528
|
process.stdout.write(` ${c3.dim("Use /telegram to toggle off, or /telegram stop")}
|
|
593952
594529
|
|
|
@@ -594222,6 +594799,8 @@ Telegram response contract:
|
|
|
594222
594799
|
groupSkipLogAt = /* @__PURE__ */ new Map();
|
|
594223
594800
|
/** Telegram interaction routing profile */
|
|
594224
594801
|
interactionMode = "auto";
|
|
594802
|
+
/** Actual model context window discovered by the main TUI. */
|
|
594803
|
+
contextWindowSize = 0;
|
|
594225
594804
|
/** Event handler for forwarding sub-agent events to parent TUI */
|
|
594226
594805
|
onSubAgentEvent = null;
|
|
594227
594806
|
/** Tool policy config — user overrides from config */
|
|
@@ -594272,6 +594851,9 @@ Telegram response contract:
|
|
|
594272
594851
|
getInteractionMode() {
|
|
594273
594852
|
return this.interactionMode;
|
|
594274
594853
|
}
|
|
594854
|
+
setContextWindowSize(size) {
|
|
594855
|
+
this.contextWindowSize = Number.isFinite(size) && size > 0 ? Math.trunc(size) : 0;
|
|
594856
|
+
}
|
|
594275
594857
|
/** Update tool policy config at runtime (e.g., from /disable command) */
|
|
594276
594858
|
setToolPolicyConfig(config) {
|
|
594277
594859
|
this.toolPolicyConfig = config;
|
|
@@ -594773,6 +595355,7 @@ ${lines.join("\n")}`);
|
|
|
594773
595355
|
return sections.join("\n\n");
|
|
594774
595356
|
}
|
|
594775
595357
|
maybeLogTelegramGroupSkip(msg, reason) {
|
|
595358
|
+
if (process.env["OMNIUS_TELEGRAM_DEBUG_SKIPS"] !== "1") return;
|
|
594776
595359
|
const sessionKey = this.sessionKeyForMessage(msg);
|
|
594777
595360
|
const now = Date.now();
|
|
594778
595361
|
const last2 = this.groupSkipLogAt.get(sessionKey) ?? 0;
|
|
@@ -594780,16 +595363,27 @@ ${lines.join("\n")}`);
|
|
|
594780
595363
|
this.groupSkipLogAt.set(sessionKey, now);
|
|
594781
595364
|
this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, `${reason} (context retained)`));
|
|
594782
595365
|
}
|
|
595366
|
+
telegramMessageAddressesBot(msg) {
|
|
595367
|
+
const bot = this.state.botUsername.trim().replace(/^@/, "").toLowerCase();
|
|
595368
|
+
if (!bot) return false;
|
|
595369
|
+
const mentioned = (msg.mentionedUsernames ?? []).some(
|
|
595370
|
+
(name10) => name10.trim().replace(/^@/, "").toLowerCase() === bot
|
|
595371
|
+
);
|
|
595372
|
+
if (mentioned) return true;
|
|
595373
|
+
if (msg.replyToUsername && msg.replyToUsername.trim().replace(/^@/, "").toLowerCase() === bot) return true;
|
|
595374
|
+
return false;
|
|
595375
|
+
}
|
|
594783
595376
|
async inferTelegramInteractionDecision(msg, toolContext) {
|
|
594784
595377
|
const config = this.agentConfig;
|
|
594785
595378
|
const forcedRoute = this.interactionMode === "chat" || this.interactionMode === "action" ? this.interactionMode : null;
|
|
594786
595379
|
const isGroup = msg.chatType !== "private";
|
|
595380
|
+
const addressesBot = this.telegramMessageAddressesBot(msg);
|
|
594787
595381
|
if (!config) {
|
|
594788
595382
|
return {
|
|
594789
|
-
route: forcedRoute ?? "action",
|
|
594790
|
-
shouldReply: !isGroup,
|
|
595383
|
+
route: forcedRoute ?? (isGroup ? "action" : "chat"),
|
|
595384
|
+
shouldReply: !isGroup || addressesBot,
|
|
594791
595385
|
confidence: 0,
|
|
594792
|
-
reason: isGroup ? "router inference unavailable; public group fails closed without keyword heuristics" : "router inference unavailable; private chat defaults to reply",
|
|
595386
|
+
reason: isGroup ? addressesBot ? "router inference unavailable; Telegram message directly addresses the bot" : "router inference unavailable; public group fails closed without keyword heuristics" : "router inference unavailable; private chat defaults to quick reply",
|
|
594793
595387
|
source: "inference-unavailable"
|
|
594794
595388
|
};
|
|
594795
595389
|
}
|
|
@@ -594810,6 +595404,7 @@ ${lines.join("\n")}`);
|
|
|
594810
595404
|
`Route meanings:`,
|
|
594811
595405
|
`- chat: a short conversational answer can be produced without tools.`,
|
|
594812
595406
|
`- action: tools, workspace context, media processing, web lookup, delegation, or a multi-step agent loop may be needed.`,
|
|
595407
|
+
`Route discipline: greetings, acknowledgements, casual tone/style discussion, and simple conversational questions are chat. Use action only when the message asks you to inspect, create, change, send, remember, search, analyze media, or otherwise do tool-backed work.`,
|
|
594813
595408
|
``,
|
|
594814
595409
|
`Reply discretion: infer from the live thread, speaker relationships, direct mentions, replies, tone, and current message. Do not use static keyword rules.`,
|
|
594815
595410
|
`Private chats: should_reply is normally true.`,
|
|
@@ -594818,9 +595413,12 @@ ${lines.join("\n")}`);
|
|
|
594818
595413
|
``,
|
|
594819
595414
|
`Tool context: ${toolContext}`,
|
|
594820
595415
|
`Bot username: ${this.state.botUsername || "unknown"}`,
|
|
595416
|
+
`Current message directly addresses this bot: ${addressesBot ? "yes" : "no"}`,
|
|
594821
595417
|
`Current chat type: ${msg.chatType}`,
|
|
594822
595418
|
`Current sender: ${telegramSpeakerLabel(msg)}`,
|
|
594823
595419
|
msg.replyToMessageId ? `Current message replies to message_id ${msg.replyToMessageId}` : "",
|
|
595420
|
+
msg.replyToUsername ? `Current message replies to @${msg.replyToUsername}` : "",
|
|
595421
|
+
(msg.mentionedUsernames ?? []).length > 0 ? `Current message mentions: ${(msg.mentionedUsernames ?? []).map((name10) => `@${name10}`).join(", ")}` : "",
|
|
594824
595422
|
msg.media ? `Current message has media: ${summarizeTelegramMessageAttachments(msg)}` : "",
|
|
594825
595423
|
``,
|
|
594826
595424
|
context2,
|
|
@@ -594840,7 +595438,7 @@ ${msg.text}`
|
|
|
594840
595438
|
tools: [],
|
|
594841
595439
|
temperature: 0,
|
|
594842
595440
|
maxTokens: 220,
|
|
594843
|
-
timeoutMs: Math.min(config.timeoutMs ?? 3e4, 15e3),
|
|
595441
|
+
timeoutMs: Math.min(Math.max(config.timeoutMs ?? 3e4, 5e3), 15e3),
|
|
594844
595442
|
think: false
|
|
594845
595443
|
});
|
|
594846
595444
|
const text = result.choices[0]?.message?.content ?? "";
|
|
@@ -594851,10 +595449,10 @@ ${msg.text}`
|
|
|
594851
595449
|
} catch {
|
|
594852
595450
|
}
|
|
594853
595451
|
return {
|
|
594854
|
-
route: forcedRoute ?? "action",
|
|
594855
|
-
shouldReply: !isGroup,
|
|
595452
|
+
route: forcedRoute ?? (isGroup ? "action" : "chat"),
|
|
595453
|
+
shouldReply: !isGroup || addressesBot,
|
|
594856
595454
|
confidence: 0,
|
|
594857
|
-
reason: isGroup ? "router inference failed; public group fails closed without keyword heuristics" : "router inference failed; private chat defaults to reply",
|
|
595455
|
+
reason: isGroup ? addressesBot ? "router inference failed; Telegram message directly addresses the bot" : "router inference failed; public group fails closed without keyword heuristics" : "router inference failed; private chat defaults to quick reply",
|
|
594858
595456
|
source: "inference-unavailable"
|
|
594859
595457
|
};
|
|
594860
595458
|
}
|
|
@@ -594868,6 +595466,19 @@ ${msg.text}`
|
|
|
594868
595466
|
return `Workspace context unavailable: ${reason}`;
|
|
594869
595467
|
}
|
|
594870
595468
|
}
|
|
595469
|
+
telegramFallbackCompactionThreshold(modelTier) {
|
|
595470
|
+
if (modelTier === "small") return 12e3;
|
|
595471
|
+
if (modelTier === "medium") return 24e3;
|
|
595472
|
+
return 4e4;
|
|
595473
|
+
}
|
|
595474
|
+
telegramWorkspaceBudget(profile) {
|
|
595475
|
+
if (this.contextWindowSize > 0) {
|
|
595476
|
+
const ratio = profile === "chat" ? 0.08 : 0.12;
|
|
595477
|
+
const floor = profile === "chat" ? 16e3 : 24e3;
|
|
595478
|
+
return Math.max(floor, Math.floor(this.contextWindowSize * ratio));
|
|
595479
|
+
}
|
|
595480
|
+
return profile === "chat" ? 16e3 : 24e3;
|
|
595481
|
+
}
|
|
594871
595482
|
buildPrimaryTuiSessionContext(telegramSessionId) {
|
|
594872
595483
|
const primarySessionId = process.env["OMNIUS_SESSION_ID"] || process.env["OMNIUS_TUI_SESSION_ID"] || "";
|
|
594873
595484
|
if (!primarySessionId || primarySessionId === telegramSessionId) return "";
|
|
@@ -594925,7 +595536,7 @@ ${ADMIN_CHAT_PROFILE_PROMPT}`);
|
|
|
594925
595536
|
if (primarySessionContext) sections.push(`## Primary TUI Session State
|
|
594926
595537
|
|
|
594927
595538
|
${primarySessionContext}`);
|
|
594928
|
-
const workspaceContext = this.buildTelegramWorkspaceContext(modelTier, profile
|
|
595539
|
+
const workspaceContext = this.buildTelegramWorkspaceContext(modelTier, this.telegramWorkspaceBudget(profile));
|
|
594929
595540
|
if (workspaceContext) sections.push(`## Workspace Context
|
|
594930
595541
|
|
|
594931
595542
|
${workspaceContext}`);
|
|
@@ -595316,7 +595927,8 @@ ${mediaContext}`;
|
|
|
595316
595927
|
toolContext,
|
|
595317
595928
|
pendingMessages: [],
|
|
595318
595929
|
creativeWorkspaceRoot: this.creativeWorkspaceRootForMessage(msg, toolContext),
|
|
595319
|
-
generatedArtifacts: []
|
|
595930
|
+
generatedArtifacts: [],
|
|
595931
|
+
surfacedToolCallFingerprints: /* @__PURE__ */ new Set()
|
|
595320
595932
|
};
|
|
595321
595933
|
this.subAgents.set(sessionKey, subAgent);
|
|
595322
595934
|
this.refreshActiveTelegramInteractionCount();
|
|
@@ -595413,7 +596025,8 @@ ${mediaContext}`;
|
|
|
595413
596025
|
toolContext,
|
|
595414
596026
|
pendingMessages: [],
|
|
595415
596027
|
creativeWorkspaceRoot: this.creativeWorkspaceRootForMessage(msg, toolContext),
|
|
595416
|
-
generatedArtifacts: []
|
|
596028
|
+
generatedArtifacts: [],
|
|
596029
|
+
surfacedToolCallFingerprints: /* @__PURE__ */ new Set()
|
|
595417
596030
|
};
|
|
595418
596031
|
this.subAgents.set(sessionKey, subAgent);
|
|
595419
596032
|
this.refreshActiveTelegramInteractionCount();
|
|
@@ -595684,6 +596297,7 @@ ${mediaContext}` : ""}`
|
|
|
595684
596297
|
const isGroup = msg.chatType !== "private";
|
|
595685
596298
|
const creativeWorkspace = subAgent.creativeWorkspaceRoot ? formatTelegramCreativeWorkspacePrompt(subAgent.creativeWorkspaceRoot) : "";
|
|
595686
596299
|
const sessionContext = this.buildTelegramSessionContext(msg, ctx3, profile, modelTier);
|
|
596300
|
+
const contextWindowSize = this.contextWindowSize;
|
|
595687
596301
|
const backend = new OllamaAgenticBackend(
|
|
595688
596302
|
config.backendUrl,
|
|
595689
596303
|
config.model,
|
|
@@ -595695,7 +596309,8 @@ ${mediaContext}` : ""}`
|
|
|
595695
596309
|
temperature: 0.3,
|
|
595696
596310
|
requestTimeoutMs: config.timeoutMs,
|
|
595697
596311
|
taskTimeoutMs: isAdminDM ? config.timeoutMs * 3 : config.timeoutMs,
|
|
595698
|
-
compactionThreshold: modelTier
|
|
596312
|
+
compactionThreshold: this.telegramFallbackCompactionThreshold(modelTier),
|
|
596313
|
+
contextWindowSize,
|
|
595699
596314
|
modelTier,
|
|
595700
596315
|
streamEnabled: true,
|
|
595701
596316
|
dynamicContext: sessionContext.context,
|
|
@@ -595714,8 +596329,20 @@ ${mediaContext}` : ""}`
|
|
|
595714
596329
|
runner.registerTools(tools);
|
|
595715
596330
|
runner.onEvent((event) => {
|
|
595716
596331
|
if (subAgent.aborted) return;
|
|
595717
|
-
|
|
596332
|
+
let suppressExternalEvent = false;
|
|
596333
|
+
if (event.type === "tool_call" && event.toolName) {
|
|
596334
|
+
const fp = `${event.toolName}:${stableTelegramValueKey(event.toolArgs ?? {})}`;
|
|
596335
|
+
if (subAgent.surfacedToolCallFingerprints.has(fp)) {
|
|
596336
|
+
suppressExternalEvent = true;
|
|
596337
|
+
} else {
|
|
596338
|
+
subAgent.surfacedToolCallFingerprints.add(fp);
|
|
596339
|
+
}
|
|
596340
|
+
}
|
|
596341
|
+
if (!suppressExternalEvent) {
|
|
596342
|
+
this.onSubAgentEvent?.(msg.chatId, msg.username, event);
|
|
596343
|
+
}
|
|
595718
596344
|
if (event.type === "tool_call" && event.toolName) {
|
|
596345
|
+
if (suppressExternalEvent) return;
|
|
595719
596346
|
const argsPreview = event.toolArgs ? JSON.stringify(event.toolArgs).slice(0, 100) : "";
|
|
595720
596347
|
this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `tool: ${event.toolName}(${argsPreview})`);
|
|
595721
596348
|
} else if (event.type === "tool_result" && event.toolName) {
|
|
@@ -595728,8 +596355,11 @@ ${mediaContext}` : ""}`
|
|
|
595728
596355
|
}
|
|
595729
596356
|
} else if (event.type === "status" && event.content) {
|
|
595730
596357
|
this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `status: ${event.content}`);
|
|
595731
|
-
} else if (event.type === "assistant_text" && event.content) {
|
|
596358
|
+
} else if (event.type === "assistant_text" && event.content && event.source !== "task_complete_summary") {
|
|
595732
596359
|
subAgent.assistantText = event.content;
|
|
596360
|
+
} else if (event.type === "stream_start") {
|
|
596361
|
+
subAgent.accumulated = "";
|
|
596362
|
+
subAgent.streamText = "";
|
|
595733
596363
|
} else if (event.type === "stream_end" && event.content) {
|
|
595734
596364
|
subAgent.streamText = event.content;
|
|
595735
596365
|
}
|
|
@@ -595792,6 +596422,8 @@ ${msg.text}`;
|
|
|
595792
596422
|
const toolHint = [
|
|
595793
596423
|
"You have access to isolated per-chat memory (memory_write, memory_read, memory_search) scoped to this conversation.",
|
|
595794
596424
|
"You can remember facts about users and retrieve them later. You also have web_search and web_fetch to look up information.",
|
|
596425
|
+
"If the user asks you to create or send a file, image, or audio artifact, use the scoped creative tools. The bridge will attach generated files back to Telegram when tool results record them.",
|
|
596426
|
+
"For image generation requests, decide from the conversation whether generate_image is appropriate; do not ask the user to use a hardcoded shortcut when the request is clear.",
|
|
595795
596427
|
creativeWorkspace
|
|
595796
596428
|
].filter(Boolean).join("\n\n");
|
|
595797
596429
|
userPrompt = `${systemPrompt}${discretionPrompt}
|
|
@@ -595939,6 +596571,13 @@ ${creativeWorkspace}` : ""}`;
|
|
|
595939
596571
|
fullSubAgentTool
|
|
595940
596572
|
];
|
|
595941
596573
|
const allTools = context2 === "telegram-admin-dm" ? adminTools : sharedReadMemoryWebTools;
|
|
596574
|
+
if (this.contextWindowSize > 0) {
|
|
596575
|
+
for (const tool of allTools) {
|
|
596576
|
+
if ("setContextWindowSize" in tool && typeof tool.setContextWindowSize === "function") {
|
|
596577
|
+
tool.setContextWindowSize(this.contextWindowSize);
|
|
596578
|
+
}
|
|
596579
|
+
}
|
|
596580
|
+
}
|
|
595942
596581
|
let adaptedTools = allTools.map((tool) => adaptTool5(tool, todoSessionId));
|
|
595943
596582
|
adaptedTools = applyToolPolicy(adaptedTools, context2, this.toolPolicyConfig);
|
|
595944
596583
|
if (context2 !== "telegram-admin-dm") {
|
|
@@ -621769,13 +622408,14 @@ async function renderAsciiPreviewForImage(imagePath, displayPath, title, writer)
|
|
|
621769
622408
|
}
|
|
621770
622409
|
}
|
|
621771
622410
|
async function renderAsciiPreviewForToolResult(toolName, output, repoRoot, writer) {
|
|
621772
|
-
if (
|
|
622411
|
+
if (!output) return;
|
|
621773
622412
|
try {
|
|
621774
622413
|
const { extractSavedImagePath: extractSavedImagePath2 } = await Promise.resolve().then(() => (init_image_ascii_preview(), image_ascii_preview_exports));
|
|
621775
622414
|
const imagePath = extractSavedImagePath2(output, repoRoot);
|
|
621776
622415
|
if (!imagePath) return;
|
|
621777
622416
|
const displayPath = relative13(repoRoot, imagePath).startsWith("..") ? imagePath : relative13(repoRoot, imagePath);
|
|
621778
|
-
|
|
622417
|
+
const title = toolName === "generate_image" ? "Generated image" : toolName === "screenshot" ? "Screenshot" : toolName === "camera_capture" ? "Camera frame" : "Image";
|
|
622418
|
+
await renderAsciiPreviewForImage(imagePath, displayPath, title, writer);
|
|
621779
622419
|
} catch {
|
|
621780
622420
|
}
|
|
621781
622421
|
}
|
|
@@ -622926,7 +623566,7 @@ ${entry.fullContent}`
|
|
|
622926
623566
|
}
|
|
622927
623567
|
});
|
|
622928
623568
|
}
|
|
622929
|
-
if (event.success
|
|
623569
|
+
if (event.success) {
|
|
622930
623570
|
void renderAsciiPreviewForToolResult(event.toolName, event.content ?? "", repoRoot, contentWrite);
|
|
622931
623571
|
}
|
|
622932
623572
|
if (voice?.enabled && voice.voiceMode === "voicechat" && _voiceChatSession2?.isActive && event.toolName === "task_complete") {
|
|
@@ -624211,6 +624851,7 @@ ${result.summary}`
|
|
|
624211
624851
|
resolvedContextWindowSize = ctxSize;
|
|
624212
624852
|
statusBar.setContextWindowSize(ctxSize);
|
|
624213
624853
|
setActiveTaskContextWindowSize(ctxSize);
|
|
624854
|
+
telegramBridge?.setContextWindowSize(ctxSize);
|
|
624214
624855
|
}
|
|
624215
624856
|
}).catch(() => {
|
|
624216
624857
|
});
|
|
@@ -626139,6 +626780,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
626139
626780
|
currentConfig,
|
|
626140
626781
|
repoRoot
|
|
626141
626782
|
);
|
|
626783
|
+
if (resolvedContextWindowSize > 0) {
|
|
626784
|
+
telegramBridge.setContextWindowSize(resolvedContextWindowSize);
|
|
626785
|
+
}
|
|
626142
626786
|
telegramBridge.setInteractionMode(savedSettings.telegramMode ?? "auto");
|
|
626143
626787
|
if (adminId) {
|
|
626144
626788
|
telegramBridge.setAdmin(adminId);
|
|
@@ -626180,7 +626824,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
626180
626824
|
}
|
|
626181
626825
|
});
|
|
626182
626826
|
telegramBridge.setOnSubAgentEvent((chatId, username, event) => {
|
|
626183
|
-
if (event.type === "tool_call" && event.toolName) {
|
|
626827
|
+
if (event.type === "tool_call" && event.toolName && event.toolName !== "task_complete") {
|
|
626184
626828
|
const argsPreview = event.toolArgs ? JSON.stringify(event.toolArgs).slice(0, 60) : "";
|
|
626185
626829
|
writeContent(
|
|
626186
626830
|
() => renderTelegramSubAgentToolCall(
|
|
@@ -626189,7 +626833,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
626189
626833
|
argsPreview
|
|
626190
626834
|
)
|
|
626191
626835
|
);
|
|
626192
|
-
} else if (event.type === "status" && event.content) {
|
|
626836
|
+
} else if (event.type === "status" && event.content && process.env["OMNIUS_TELEGRAM_DEBUG_STATUS"] === "1") {
|
|
626193
626837
|
writeContent(
|
|
626194
626838
|
() => renderTelegramSubAgentEvent(username, event.content)
|
|
626195
626839
|
);
|
|
@@ -627207,6 +627851,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
627207
627851
|
setContextWindowSize: (size) => {
|
|
627208
627852
|
resolvedContextWindowSize = size;
|
|
627209
627853
|
statusBar.setContextWindowSize(size);
|
|
627854
|
+
telegramBridge?.setContextWindowSize(size);
|
|
627210
627855
|
},
|
|
627211
627856
|
setCapabilities: (caps) => {
|
|
627212
627857
|
resolvedCaps = caps;
|