omnius 1.0.198 → 1.0.199
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 +220 -18
- package/docs/rest/QUICKREF.md +2 -2
- package/docs/rest/auth-and-scopes.md +1 -1
- package/docs/rest/endpoints/run.md +2 -2
- package/docs/rest/endpoints/tools.md +5 -5
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -260097,6 +260097,31 @@ function approxImageDownloadBytes(preset) {
|
|
|
260097
260097
|
}
|
|
260098
260098
|
return gigabytesToBytes(4);
|
|
260099
260099
|
}
|
|
260100
|
+
function imagePresetDependencyModels(preset, selectedModel) {
|
|
260101
|
+
const models = [
|
|
260102
|
+
selectedModel,
|
|
260103
|
+
preset?.diffusersBaseModel,
|
|
260104
|
+
preset?.textEncoderModel,
|
|
260105
|
+
...preset?.loraAdapters?.map((adapter) => adapter.repoId) ?? []
|
|
260106
|
+
].filter((value2) => Boolean(value2 && value2.trim()));
|
|
260107
|
+
return [...new Set(models)];
|
|
260108
|
+
}
|
|
260109
|
+
function diffusersRunnerModelArgs(model) {
|
|
260110
|
+
const preset = getImageGenerationPreset(model);
|
|
260111
|
+
const runnerModel = preset?.diffusersBaseModel ?? model;
|
|
260112
|
+
const argv = ["--model", runnerModel];
|
|
260113
|
+
if (runnerModel !== model)
|
|
260114
|
+
argv.push("--display-model", model);
|
|
260115
|
+
if (preset?.textEncoderModel) {
|
|
260116
|
+
argv.push("--text-encoder", preset.textEncoderModel);
|
|
260117
|
+
if (preset.textEncoderTarget)
|
|
260118
|
+
argv.push("--text-encoder-target", preset.textEncoderTarget);
|
|
260119
|
+
}
|
|
260120
|
+
for (const adapter of preset?.loraAdapters ?? []) {
|
|
260121
|
+
argv.push("--lora", JSON.stringify(adapter));
|
|
260122
|
+
}
|
|
260123
|
+
return argv;
|
|
260124
|
+
}
|
|
260100
260125
|
async function ensureImageGenerationCacheDirs(repoRoot) {
|
|
260101
260126
|
const env2 = imageGenerationPythonEnv(repoRoot);
|
|
260102
260127
|
await Promise.all([
|
|
@@ -260228,7 +260253,7 @@ function parseRunnerJson(stdout) {
|
|
|
260228
260253
|
}
|
|
260229
260254
|
return null;
|
|
260230
260255
|
}
|
|
260231
|
-
var DEFAULT_DIFFUSERS_IMAGE_MODEL, DEFAULT_OLLAMA_IMAGE_MODEL, LEGACY_SDXL_TURBO_MODEL, SANA_1_5_1_6B_MODEL, SANA_1_5_4_8B_MODEL, SANA_1_6B_MULTILING_MODEL, SANA_1_6B_2K_MODEL, SANA_1_6B_4K_MODEL, SANA_SPRINT_0_6B_MODEL, SECONDARY_FLUX_DEV_MODEL, SECONDARY_FLUX_DEV_MIRROR_MODEL, SECONDARY_FLUX_DEV_COMFY_MODEL, SECONDARY_FLUX_FILL_MODEL, SECONDARY_FLUX_FILL_FP8_MODEL, SECONDARY_FLUX2_MODEL, OFFICIAL_BFL_ORG, IMAGE_GENERATION_MODEL_REPLACEMENTS, DIFFUSERS_PYTHON_PACKAGES, SDCPP_PYTHON_PACKAGES, IMAGE_GENERATION_MODEL_PRESETS, IMAGE_GENERATION_QUALITY_LADDER, OLLAMA_IMAGE_MODELS, DIFFUSERS_RUNNER, SDCPP_RUNNER, ImageGenerateTool;
|
|
260256
|
+
var DEFAULT_DIFFUSERS_IMAGE_MODEL, DEFAULT_OLLAMA_IMAGE_MODEL, LEGACY_SDXL_TURBO_MODEL, SANA_1_5_1_6B_MODEL, SANA_1_5_4_8B_MODEL, SANA_1_6B_MULTILING_MODEL, SANA_1_6B_2K_MODEL, SANA_1_6B_4K_MODEL, SANA_SPRINT_0_6B_MODEL, SECONDARY_FLUX_DEV_MODEL, SECONDARY_FLUX_DEV_MIRROR_MODEL, SECONDARY_FLUX_DEV_COMFY_MODEL, SECONDARY_FLUX_FILL_MODEL, SECONDARY_FLUX_FILL_FP8_MODEL, SECONDARY_FLUX2_MODEL, OFFICIAL_FLUX1_DEV_MODEL, OFFICIAL_FLUX2_KLEIN_9B_MODEL, PONPOKE_FLUX2_UNCENSORED_TEXT_ENCODER_MODEL, LUSTLY_FLUX_UNCENSORED_LORA_MODEL, KENERATE_FLUX_UNCENSORED_LORA_MODEL, OFFICIAL_BFL_ORG, IMAGE_GENERATION_MODEL_REPLACEMENTS, DIFFUSERS_PYTHON_PACKAGES, SDCPP_PYTHON_PACKAGES, IMAGE_GENERATION_MODEL_PRESETS, IMAGE_GENERATION_QUALITY_LADDER, OLLAMA_IMAGE_MODELS, DIFFUSERS_RUNNER, SDCPP_RUNNER, ImageGenerateTool;
|
|
260232
260257
|
var init_image_generate = __esm({
|
|
260233
260258
|
"packages/execution/dist/tools/image-generate.js"() {
|
|
260234
260259
|
"use strict";
|
|
@@ -260252,6 +260277,11 @@ var init_image_generate = __esm({
|
|
|
260252
260277
|
SECONDARY_FLUX_FILL_MODEL = "diffusers/FLUX.1-Fill-dev-nf4";
|
|
260253
260278
|
SECONDARY_FLUX_FILL_FP8_MODEL = "boricuapab/flux1-fill-dev-fp8";
|
|
260254
260279
|
SECONDARY_FLUX2_MODEL = "x/flux2-klein";
|
|
260280
|
+
OFFICIAL_FLUX1_DEV_MODEL = "black-forest-labs/FLUX.1-dev";
|
|
260281
|
+
OFFICIAL_FLUX2_KLEIN_9B_MODEL = "black-forest-labs/FLUX.2-klein-9B";
|
|
260282
|
+
PONPOKE_FLUX2_UNCENSORED_TEXT_ENCODER_MODEL = "ponpoke/flux2-klein-9b-uncensored-text-encoder";
|
|
260283
|
+
LUSTLY_FLUX_UNCENSORED_LORA_MODEL = "lustlyai/Flux_Lustly.ai_Uncensored_nsfw_v1";
|
|
260284
|
+
KENERATE_FLUX_UNCENSORED_LORA_MODEL = "kenerateai/Flux-uncensored";
|
|
260255
260285
|
OFFICIAL_BFL_ORG = "black-forest-labs";
|
|
260256
260286
|
IMAGE_GENERATION_MODEL_REPLACEMENTS = /* @__PURE__ */ new Map([
|
|
260257
260287
|
[officialBflModel("FLUX.1-dev"), SECONDARY_FLUX_DEV_MODEL],
|
|
@@ -260274,6 +260304,7 @@ var init_image_generate = __esm({
|
|
|
260274
260304
|
"transformers",
|
|
260275
260305
|
"accelerate",
|
|
260276
260306
|
"safetensors",
|
|
260307
|
+
"peft",
|
|
260277
260308
|
"pillow",
|
|
260278
260309
|
"sentencepiece",
|
|
260279
260310
|
"protobuf"
|
|
@@ -260387,6 +260418,76 @@ var init_image_generate = __esm({
|
|
|
260387
260418
|
fallbackFor: [SECONDARY_FLUX_FILL_MODEL],
|
|
260388
260419
|
note: "Traceable FP8 fallback for FLUX.1 Fill dev from the research package."
|
|
260389
260420
|
},
|
|
260421
|
+
{
|
|
260422
|
+
id: PONPOKE_FLUX2_UNCENSORED_TEXT_ENCODER_MODEL,
|
|
260423
|
+
label: "FLUX.2 Klein 9B uncensored text encoder",
|
|
260424
|
+
backend: "diffusers",
|
|
260425
|
+
install: 'python3 .omnius/image-gen/diffusers_text2image.py --model black-forest-labs/FLUX.2-klein-9B --text-encoder ponpoke/flux2-klein-9b-uncensored-text-encoder --steps 4 --guidance 1 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png',
|
|
260426
|
+
category: "Adult-capable FLUX adapter",
|
|
260427
|
+
sizeClass: "FLUX.2 Klein 9B text-encoder override",
|
|
260428
|
+
quality: "Uncensored FLUX.2 Klein text-encoder override; uses the official FLUX.2 Klein 9B base pipeline and replaces the prompt encoder when the installed Diffusers stack supports that component layout.",
|
|
260429
|
+
minVramGB: 24,
|
|
260430
|
+
recommendedVramGB: 32,
|
|
260431
|
+
deployment: "Diffusers Flux2KleinPipeline over black-forest-labs/FLUX.2-klein-9B with a replacement text encoder. Requires Hugging Face access/license acceptance for the BFL base and the text-encoder repo.",
|
|
260432
|
+
steps: 4,
|
|
260433
|
+
guidance: 1,
|
|
260434
|
+
width: 1024,
|
|
260435
|
+
height: 1024,
|
|
260436
|
+
diffusersBaseModel: OFFICIAL_FLUX2_KLEIN_9B_MODEL,
|
|
260437
|
+
textEncoderModel: PONPOKE_FLUX2_UNCENSORED_TEXT_ENCODER_MODEL,
|
|
260438
|
+
textEncoderTarget: "auto",
|
|
260439
|
+
approxDownloadGB: 36,
|
|
260440
|
+
note: "Adapter-style preset: loads the gated FLUX.2 Klein 9B base and swaps in the ponpoke text encoder. Not in the automatic fallback ladder."
|
|
260441
|
+
},
|
|
260442
|
+
{
|
|
260443
|
+
id: LUSTLY_FLUX_UNCENSORED_LORA_MODEL,
|
|
260444
|
+
label: "Flux Lustly uncensored LoRA",
|
|
260445
|
+
backend: "diffusers",
|
|
260446
|
+
install: `python3 .omnius/image-gen/diffusers_text2image.py --model black-forest-labs/FLUX.1-dev --lora '{"repoId":"lustlyai/Flux_Lustly.ai_Uncensored_nsfw_v1","weightName":"flux_lustly-ai_v1.safetensors","adapterName":"v1","adapterWeight":1}' --steps 20 --guidance 4 --width 768 --height 768 --prompt "..." --output .omnius/images/out.png`,
|
|
260447
|
+
category: "Adult-capable FLUX adapter",
|
|
260448
|
+
sizeClass: "FLUX.1-dev LoRA adapter",
|
|
260449
|
+
quality: "Adult-capable FLUX.1-dev LoRA tested by its publisher on full FLUX dev and schnell. Listed as an explicit opt-in model, not part of automatic fallback.",
|
|
260450
|
+
minVramGB: 16,
|
|
260451
|
+
recommendedVramGB: 24,
|
|
260452
|
+
deployment: "Diffusers LoRA over black-forest-labs/FLUX.1-dev. Requires Hugging Face access/license acceptance for the gated BFL base model and the adapter terms.",
|
|
260453
|
+
steps: 20,
|
|
260454
|
+
guidance: 4,
|
|
260455
|
+
width: 768,
|
|
260456
|
+
height: 768,
|
|
260457
|
+
diffusersBaseModel: OFFICIAL_FLUX1_DEV_MODEL,
|
|
260458
|
+
loraAdapters: [{
|
|
260459
|
+
repoId: LUSTLY_FLUX_UNCENSORED_LORA_MODEL,
|
|
260460
|
+
weightName: "flux_lustly-ai_v1.safetensors",
|
|
260461
|
+
adapterName: "v1",
|
|
260462
|
+
adapterWeight: 1
|
|
260463
|
+
}],
|
|
260464
|
+
approxDownloadGB: 24,
|
|
260465
|
+
note: "Adapter-style preset: loads FLUX.1-dev then applies the Lustly LoRA. Explicit selection only."
|
|
260466
|
+
},
|
|
260467
|
+
{
|
|
260468
|
+
id: KENERATE_FLUX_UNCENSORED_LORA_MODEL,
|
|
260469
|
+
label: "Kenerate Flux uncensored LoRA",
|
|
260470
|
+
backend: "diffusers",
|
|
260471
|
+
install: `python3 .omnius/image-gen/diffusers_text2image.py --model black-forest-labs/FLUX.1-dev --lora '{"repoId":"kenerateai/Flux-uncensored","adapterName":"kenerate","adapterWeight":1}' --steps 20 --guidance 3.5 --width 1024 --height 1024 --prompt "..." --output .omnius/images/out.png`,
|
|
260472
|
+
category: "Adult-capable FLUX adapter",
|
|
260473
|
+
sizeClass: "FLUX.1-dev LoRA adapter",
|
|
260474
|
+
quality: "Community FLUX.1-dev LoRA. Hugging Face currently marks the model card as removed, so availability may fail at download time; kept as a selectable explicit model because the repo still advertises a Diffusers LoRA load path.",
|
|
260475
|
+
minVramGB: 16,
|
|
260476
|
+
recommendedVramGB: 24,
|
|
260477
|
+
deployment: "Diffusers LoRA over black-forest-labs/FLUX.1-dev. Requires Hugging Face access/license acceptance for the gated BFL base model; adapter availability may vary.",
|
|
260478
|
+
steps: 20,
|
|
260479
|
+
guidance: 3.5,
|
|
260480
|
+
width: 1024,
|
|
260481
|
+
height: 1024,
|
|
260482
|
+
diffusersBaseModel: OFFICIAL_FLUX1_DEV_MODEL,
|
|
260483
|
+
loraAdapters: [{
|
|
260484
|
+
repoId: KENERATE_FLUX_UNCENSORED_LORA_MODEL,
|
|
260485
|
+
adapterName: "kenerate",
|
|
260486
|
+
adapterWeight: 1
|
|
260487
|
+
}],
|
|
260488
|
+
approxDownloadGB: 24,
|
|
260489
|
+
note: "Adapter-style preset: loads FLUX.1-dev then applies the Kenerate LoRA. The upstream card says the LoRA has been removed, so failures should be surfaced directly."
|
|
260490
|
+
},
|
|
260390
260491
|
{
|
|
260391
260492
|
id: "stabilityai/stable-diffusion-3.5-large",
|
|
260392
260493
|
label: "Stable Diffusion 3.5 Large",
|
|
@@ -260723,6 +260824,13 @@ def _device():
|
|
|
260723
260824
|
|
|
260724
260825
|
def _pipeline_class(model):
|
|
260725
260826
|
lowered = model.lower()
|
|
260827
|
+
if "flux.2" in lowered or "flux2" in lowered or "flux-2" in lowered:
|
|
260828
|
+
try:
|
|
260829
|
+
from diffusers import Flux2KleinPipeline
|
|
260830
|
+
return Flux2KleinPipeline
|
|
260831
|
+
except Exception:
|
|
260832
|
+
from diffusers import DiffusionPipeline
|
|
260833
|
+
return DiffusionPipeline
|
|
260726
260834
|
if "flux" in lowered:
|
|
260727
260835
|
from diffusers import FluxPipeline
|
|
260728
260836
|
return FluxPipeline
|
|
@@ -260749,13 +260857,85 @@ def _pipeline_class(model):
|
|
|
260749
260857
|
def _large_model(model):
|
|
260750
260858
|
lowered = model.lower()
|
|
260751
260859
|
return any(token in lowered for token in [
|
|
260752
|
-
"flux.1", "flux.2", "stable-diffusion-3.5", "hunyuan", "janus",
|
|
260860
|
+
"flux.1", "flux.2", "flux2", "stable-diffusion-3.5", "hunyuan", "janus",
|
|
260753
260861
|
"sana1.5_4.8b", "sana_1600m_2kpx", "sana_1600m_4kpx",
|
|
260754
260862
|
])
|
|
260755
260863
|
|
|
260864
|
+
def _parse_lora_specs(raw_specs):
|
|
260865
|
+
specs = []
|
|
260866
|
+
for raw in raw_specs or []:
|
|
260867
|
+
if not raw:
|
|
260868
|
+
continue
|
|
260869
|
+
try:
|
|
260870
|
+
parsed = json.loads(raw)
|
|
260871
|
+
if isinstance(parsed, str):
|
|
260872
|
+
parsed = {"repoId": parsed}
|
|
260873
|
+
if isinstance(parsed, dict) and parsed.get("repoId"):
|
|
260874
|
+
specs.append(parsed)
|
|
260875
|
+
except Exception as exc:
|
|
260876
|
+
raise ValueError(f"Invalid --lora JSON {raw!r}: {exc}")
|
|
260877
|
+
return specs
|
|
260878
|
+
|
|
260879
|
+
def _load_lora_adapters(pipe, specs):
|
|
260880
|
+
adapter_names = []
|
|
260881
|
+
adapter_weights = []
|
|
260882
|
+
for index, spec in enumerate(specs):
|
|
260883
|
+
repo_id = str(spec.get("repoId") or "").strip()
|
|
260884
|
+
if not repo_id:
|
|
260885
|
+
continue
|
|
260886
|
+
kwargs = {}
|
|
260887
|
+
weight_name = str(spec.get("weightName") or "").strip()
|
|
260888
|
+
adapter_name = str(spec.get("adapterName") or f"adapter_{index}").strip()
|
|
260889
|
+
if weight_name:
|
|
260890
|
+
kwargs["weight_name"] = weight_name
|
|
260891
|
+
if adapter_name:
|
|
260892
|
+
kwargs["adapter_name"] = adapter_name
|
|
260893
|
+
_progress("load", f"loading LoRA adapter {repo_id}")
|
|
260894
|
+
pipe.load_lora_weights(repo_id, **kwargs)
|
|
260895
|
+
if adapter_name:
|
|
260896
|
+
adapter_names.append(adapter_name)
|
|
260897
|
+
adapter_weights.append(float(spec.get("adapterWeight", 1.0)))
|
|
260898
|
+
if adapter_names and hasattr(pipe, "set_adapters"):
|
|
260899
|
+
_progress("load", f"activating {len(adapter_names)} LoRA adapter(s)")
|
|
260900
|
+
pipe.set_adapters(adapter_names, adapter_weights=adapter_weights)
|
|
260901
|
+
|
|
260902
|
+
def _target_text_encoder_attrs(pipe, target, repo_id):
|
|
260903
|
+
explicit = str(target or "").strip()
|
|
260904
|
+
if explicit and explicit != "auto":
|
|
260905
|
+
return [explicit]
|
|
260906
|
+
lowered = repo_id.lower()
|
|
260907
|
+
preferred = ["text_encoder_3", "text_encoder_2", "text_encoder"] if ("qwen" in lowered or "flux2" in lowered or "klein" in lowered) else ["text_encoder", "text_encoder_2", "text_encoder_3"]
|
|
260908
|
+
return [name for name in preferred if hasattr(pipe, name)]
|
|
260909
|
+
|
|
260910
|
+
def _tokenizer_attr_for_text_encoder(attr):
|
|
260911
|
+
if attr == "text_encoder":
|
|
260912
|
+
return "tokenizer"
|
|
260913
|
+
if attr.startswith("text_encoder_"):
|
|
260914
|
+
return "tokenizer_" + attr.split("_")[-1]
|
|
260915
|
+
return "tokenizer"
|
|
260916
|
+
|
|
260917
|
+
def _replace_text_encoder(pipe, repo_id, target, dtype):
|
|
260918
|
+
if not repo_id:
|
|
260919
|
+
return
|
|
260920
|
+
from transformers import AutoModel, AutoTokenizer
|
|
260921
|
+
attrs = _target_text_encoder_attrs(pipe, target, repo_id)
|
|
260922
|
+
if not attrs:
|
|
260923
|
+
raise ValueError(f"Pipeline has no text_encoder component compatible with text encoder override {repo_id}")
|
|
260924
|
+
attr = attrs[0]
|
|
260925
|
+
tokenizer_attr = _tokenizer_attr_for_text_encoder(attr)
|
|
260926
|
+
_progress("load", f"loading replacement text encoder {repo_id} into {attr}")
|
|
260927
|
+
tokenizer = AutoTokenizer.from_pretrained(repo_id, trust_remote_code=True)
|
|
260928
|
+
text_encoder = AutoModel.from_pretrained(repo_id, torch_dtype=dtype, trust_remote_code=True)
|
|
260929
|
+
setattr(pipe, attr, text_encoder)
|
|
260930
|
+
if hasattr(pipe, tokenizer_attr):
|
|
260931
|
+
setattr(pipe, tokenizer_attr, tokenizer)
|
|
260932
|
+
else:
|
|
260933
|
+
_progress("load", f"pipeline has no {tokenizer_attr}; replaced {attr} only")
|
|
260934
|
+
|
|
260756
260935
|
def main():
|
|
260757
260936
|
parser = argparse.ArgumentParser()
|
|
260758
260937
|
parser.add_argument("--model", required=True)
|
|
260938
|
+
parser.add_argument("--display-model", default="")
|
|
260759
260939
|
parser.add_argument("--prompt", required=True)
|
|
260760
260940
|
parser.add_argument("--output", required=True)
|
|
260761
260941
|
parser.add_argument("--width", type=int, default=512)
|
|
@@ -260765,6 +260945,9 @@ def main():
|
|
|
260765
260945
|
parser.add_argument("--seed", type=int, default=None)
|
|
260766
260946
|
parser.add_argument("--device", default="auto")
|
|
260767
260947
|
parser.add_argument("--variant", default="")
|
|
260948
|
+
parser.add_argument("--lora", action="append", default=[])
|
|
260949
|
+
parser.add_argument("--text-encoder", default="")
|
|
260950
|
+
parser.add_argument("--text-encoder-target", default="auto")
|
|
260768
260951
|
parser.add_argument("--prewarm", action="store_true")
|
|
260769
260952
|
args = parser.parse_args()
|
|
260770
260953
|
|
|
@@ -260793,12 +260976,19 @@ def main():
|
|
|
260793
260976
|
pipe = pipeline_cls.from_pretrained(args.model, **kwargs)
|
|
260794
260977
|
_progress("load", f"model loaded on {device}")
|
|
260795
260978
|
|
|
260979
|
+
if args.text_encoder:
|
|
260980
|
+
_replace_text_encoder(pipe, args.text_encoder, args.text_encoder_target, dtype)
|
|
260981
|
+
|
|
260796
260982
|
if "sana" in lowered_model and hasattr(pipe, "text_encoder") and pipe.text_encoder is not None:
|
|
260797
260983
|
try:
|
|
260798
260984
|
pipe.text_encoder.to(torch.bfloat16)
|
|
260799
260985
|
except Exception:
|
|
260800
260986
|
pass
|
|
260801
260987
|
|
|
260988
|
+
lora_specs = _parse_lora_specs(args.lora)
|
|
260989
|
+
if lora_specs:
|
|
260990
|
+
_load_lora_adapters(pipe, lora_specs)
|
|
260991
|
+
|
|
260802
260992
|
if hasattr(pipe, "enable_attention_slicing"):
|
|
260803
260993
|
try:
|
|
260804
260994
|
pipe.enable_attention_slicing()
|
|
@@ -260817,7 +261007,10 @@ def main():
|
|
|
260817
261007
|
print(json.dumps({
|
|
260818
261008
|
"ok": True,
|
|
260819
261009
|
"path": "",
|
|
260820
|
-
"model": args.model,
|
|
261010
|
+
"model": args.display_model or args.model,
|
|
261011
|
+
"base_model": args.model,
|
|
261012
|
+
"lora_adapters": [spec.get("repoId") for spec in lora_specs],
|
|
261013
|
+
"text_encoder": args.text_encoder or None,
|
|
260821
261014
|
"backend": "diffusers",
|
|
260822
261015
|
"device": device,
|
|
260823
261016
|
"prewarm": True,
|
|
@@ -260853,7 +261046,10 @@ def main():
|
|
|
260853
261046
|
print(json.dumps({
|
|
260854
261047
|
"ok": True,
|
|
260855
261048
|
"path": str(out),
|
|
260856
|
-
"model": args.model,
|
|
261049
|
+
"model": args.display_model or args.model,
|
|
261050
|
+
"base_model": args.model,
|
|
261051
|
+
"lora_adapters": [spec.get("repoId") for spec in lora_specs],
|
|
261052
|
+
"text_encoder": args.text_encoder or None,
|
|
260857
261053
|
"backend": "diffusers",
|
|
260858
261054
|
"device": device,
|
|
260859
261055
|
"seconds": round(time.perf_counter() - t0, 3),
|
|
@@ -260913,7 +261109,7 @@ if __name__ == "__main__":
|
|
|
260913
261109
|
`;
|
|
260914
261110
|
ImageGenerateTool = class {
|
|
260915
261111
|
name = "generate_image";
|
|
260916
|
-
description = `Generate an image from a text prompt using a local image-generation backend. Supports Ollama image models (x/flux2-klein), Python Diffusers models (Sana 1.5 1.6B default, Sana 1.5 4.8B, Sana multilingual/2K/4K, FLUX.1 dev, SD3.5 Large, SDXL Turbo, Tiny-SD, LCM, Sana Sprint), and stable-diffusion.cpp local checkpoints/GGUF. When fallback is enabled, auto generation tries ranked high-quality candidates first (Sana 1.5 above FLUX so we avoid HF gating), including community FLUX mirrors, and then falls back to smaller models if setup, download, or generation fails. Aspect ratio and resolution are model-controllable: pass aspect_ratio (e.g. "16:9", "9:16", "4:3", "3:4", "1:1", "21:9", "2:3", "3:2") to derive width/height around the selected model's preferred base resolution, or pass explicit width/height (in pixels, both rounded to a multiple of 8) when a specific size is required. A preliminary prompt-expansion stage rewrites the user's prompt into a richer, model-tuned version before generation when an LLM expander is wired; pass expand_prompt=false to skip. Saves a PNG under .omnius/images and returns the file path.`;
|
|
261112
|
+
description = `Generate an image from a text prompt using a local image-generation backend. Supports Ollama image models (x/flux2-klein), Python Diffusers models (Sana 1.5 1.6B default, Sana 1.5 4.8B, Sana multilingual/2K/4K, FLUX.1 dev, FLUX adapter/LoRA presets, SD3.5 Large, SDXL Turbo, Tiny-SD, LCM, Sana Sprint), and stable-diffusion.cpp local checkpoints/GGUF. When fallback is enabled, auto generation tries ranked high-quality candidates first (Sana 1.5 above FLUX so we avoid HF gating), including community FLUX mirrors, and then falls back to smaller models if setup, download, or generation fails. Aspect ratio and resolution are model-controllable: pass aspect_ratio (e.g. "16:9", "9:16", "4:3", "3:4", "1:1", "21:9", "2:3", "3:2") to derive width/height around the selected model's preferred base resolution, or pass explicit width/height (in pixels, both rounded to a multiple of 8) when a specific size is required. A preliminary prompt-expansion stage rewrites the user's prompt into a richer, model-tuned version before generation when an LLM expander is wired; pass expand_prompt=false to skip. Saves a PNG under .omnius/images and returns the file path.`;
|
|
260917
261113
|
parameters = {
|
|
260918
261114
|
type: "object",
|
|
260919
261115
|
properties: {
|
|
@@ -261407,7 +261603,7 @@ ${errText.slice(0, 1200)}`,
|
|
|
261407
261603
|
try {
|
|
261408
261604
|
const space = ensureDiskSpaceForDownload({
|
|
261409
261605
|
approxDownloadBytes: approxBytes,
|
|
261410
|
-
keepRepos:
|
|
261606
|
+
keepRepos: imagePresetDependencyModels(preset, args.model)
|
|
261411
261607
|
});
|
|
261412
261608
|
if (space.evicted.length > 0) {
|
|
261413
261609
|
this.emitProgress({
|
|
@@ -261442,8 +261638,7 @@ ${errText.slice(0, 1200)}`,
|
|
|
261442
261638
|
}
|
|
261443
261639
|
const result = await runProcess2(python.command, [
|
|
261444
261640
|
runner,
|
|
261445
|
-
|
|
261446
|
-
args.model,
|
|
261641
|
+
...diffusersRunnerModelArgs(args.model),
|
|
261447
261642
|
"--prompt",
|
|
261448
261643
|
"omnius prewarm",
|
|
261449
261644
|
"--output",
|
|
@@ -261617,8 +261812,7 @@ ${errText.slice(0, 800)}`,
|
|
|
261617
261812
|
}
|
|
261618
261813
|
const argv = [
|
|
261619
261814
|
runner,
|
|
261620
|
-
|
|
261621
|
-
args.model,
|
|
261815
|
+
...diffusersRunnerModelArgs(args.model),
|
|
261622
261816
|
"--prompt",
|
|
261623
261817
|
args.prompt,
|
|
261624
261818
|
"--output",
|
|
@@ -261639,7 +261833,7 @@ ${errText.slice(0, 800)}`,
|
|
|
261639
261833
|
try {
|
|
261640
261834
|
const space = ensureDiskSpaceForDownload({
|
|
261641
261835
|
approxDownloadBytes: approxBytes,
|
|
261642
|
-
keepRepos:
|
|
261836
|
+
keepRepos: imagePresetDependencyModels(preset, args.model)
|
|
261643
261837
|
});
|
|
261644
261838
|
if (space.evicted.length > 0) {
|
|
261645
261839
|
this.emitProgress({
|
|
@@ -534733,6 +534927,7 @@ __export(dist_exports, {
|
|
|
534733
534927
|
imageGenerationDir: () => imageGenerationDir,
|
|
534734
534928
|
imageGenerationModelPresets: () => imageGenerationModelPresets,
|
|
534735
534929
|
imageGenerationSetupPlan: () => imageGenerationSetupPlan,
|
|
534930
|
+
imagePresetDependencyModels: () => imagePresetDependencyModels,
|
|
534736
534931
|
inferAudioGenerationBackend: () => inferAudioGenerationBackend,
|
|
534737
534932
|
inferImageGenerationBackend: () => inferImageGenerationBackend,
|
|
534738
534933
|
inferMediaBackend: () => inferMediaBackend,
|
|
@@ -586916,9 +587111,9 @@ var init_profiles = __esm({
|
|
|
586916
587111
|
encrypted: false,
|
|
586917
587112
|
created: "2026-03-31T00:00:00Z"
|
|
586918
587113
|
},
|
|
586919
|
-
"
|
|
586920
|
-
name: "
|
|
586921
|
-
description: "
|
|
587114
|
+
"bookkeeping-tracking": {
|
|
587115
|
+
name: "bookkeeping-tracking",
|
|
587116
|
+
description: "Bookkeeping only — todos, working notes, and completion markers. No filesystem, search, shell, network, or model-generation tools.",
|
|
586922
587117
|
tools: {
|
|
586923
587118
|
allow: ["todo_write", "todo_read", "working_notes", "task_complete"],
|
|
586924
587119
|
deny: [
|
|
@@ -616212,7 +616407,13 @@ function ollamaModelDiskStats(model, sizes) {
|
|
|
616212
616407
|
}
|
|
616213
616408
|
function imageModelDiskStats(ctx3, preset, ollamaSizes) {
|
|
616214
616409
|
if (preset.backend === "ollama") return ollamaModelDiskStats(preset.id, ollamaSizes);
|
|
616215
|
-
if (preset.backend === "diffusers")
|
|
616410
|
+
if (preset.backend === "diffusers") {
|
|
616411
|
+
const root = imageGenerationDir(ctx3.repoRoot);
|
|
616412
|
+
const parts = imagePresetDependencyModels(preset, preset.id).map((model) => cachedModelDiskStats(root, model));
|
|
616413
|
+
const paths = [...new Set(parts.flatMap((part) => part.paths))];
|
|
616414
|
+
const bytes = parts.reduce((sum, part) => sum + part.bytes, 0);
|
|
616415
|
+
return { downloaded: paths.length > 0, bytes, paths };
|
|
616416
|
+
}
|
|
616216
616417
|
return { downloaded: false, bytes: 0, paths: [] };
|
|
616217
616418
|
}
|
|
616218
616419
|
function audioModelDiskStats(ctx3, preset) {
|
|
@@ -616238,7 +616439,8 @@ async function deleteImageModelWeights(ctx3, preset) {
|
|
|
616238
616439
|
if (preset.backend === "ollama") {
|
|
616239
616440
|
messages2.push(await deleteOllamaWeights(ctx3, preset.id));
|
|
616240
616441
|
} else if (preset.backend === "diffusers") {
|
|
616241
|
-
const
|
|
616442
|
+
const root = imageGenerationDir(ctx3.repoRoot);
|
|
616443
|
+
const removed = imagePresetDependencyModels(preset, preset.id).flatMap((model) => removeCachedModelPaths(root, model));
|
|
616242
616444
|
messages2.push(removed.length > 0 ? `Deleted ${removed.length} cached image model path(s) for ${preset.id}.` : `No cached image weights found for ${preset.id}.`);
|
|
616243
616445
|
} else {
|
|
616244
616446
|
messages2.push("stable-diffusion.cpp uses explicit local checkpoint paths; remove the chosen checkpoint file directly if needed.");
|
|
@@ -616261,7 +616463,7 @@ async function showImageModelsMenu(ctx3, hasLocal) {
|
|
|
616261
616463
|
};
|
|
616262
616464
|
const items = [
|
|
616263
616465
|
{ key: "setup:ollama", label: "Setup Ollama", detail: "Pull x/z-image-turbo or x/flux2-klein" },
|
|
616264
|
-
{ key: "setup:diffusers", label: "Setup Diffusers", detail: "Auto-installs
|
|
616466
|
+
{ key: "setup:diffusers", label: "Setup Diffusers", detail: "Auto-installs the shared image runtime and selected Diffusers model" },
|
|
616265
616467
|
{ key: "setup:sdcpp", label: "Setup stable-diffusion.cpp", detail: "CPU/GGUF/checkpoint route" },
|
|
616266
616468
|
{ key: "hdr:models", label: selectColors.dim("─── Models ───") },
|
|
616267
616469
|
...imageGenerationModelPresets().map(buildModelItem)
|
|
@@ -667079,7 +667281,7 @@ function handleHelp(req2, res) {
|
|
|
667079
667281
|
override: "Operators can override per-tool classification via OMNIUS_TOOL_OVERRIDES env var (JSON map of name → partial security info).",
|
|
667080
667282
|
filters: "GET /v1/tools supports ?category=, ?scope=, ?risk=, ?off_device=true|false (Q9). E.g. /v1/tools?scope=read&off_device=true returns the safe-to-expose set.",
|
|
667081
667283
|
profiles: "Tool profiles are enforced before tool exposure and again at execution. Resolution order: preset, working_directory/.omnius/profiles, ~/.omnius/profiles. Missing named profiles fail closed.",
|
|
667082
|
-
bookkeeping: "For deterministic tracking, direct-call todo_write, todo_read, working_notes, and task_complete with profile:'
|
|
667284
|
+
bookkeeping: "For deterministic tracking, direct-call todo_write, todo_read, working_notes, and task_complete with profile:'bookkeeping-tracking' and a stable session_id. Do not use /v1/run for bookkeeping-only mutations."
|
|
667083
667285
|
},
|
|
667084
667286
|
runtime_keys: {
|
|
667085
667287
|
"GET /v1/keys": "List runtime keys (admin scope). Secrets masked.",
|
package/docs/rest/QUICKREF.md
CHANGED
|
@@ -110,8 +110,8 @@ Deterministic bookkeeping without an agent run:
|
|
|
110
110
|
```bash
|
|
111
111
|
curl -s -X POST http://127.0.0.1:11435/v1/tools/todo_write/call \
|
|
112
112
|
-H 'content-type: application/json' \
|
|
113
|
-
-H 'x-omnius-session-id:
|
|
114
|
-
-d '{"profile":"
|
|
113
|
+
-H 'x-omnius-session-id: tracking-turn-123' \
|
|
114
|
+
-d '{"profile":"bookkeeping-tracking","args":{"todos":[{"content":"Create report","status":"in_progress"}]}}'
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
## Voice TTS
|
|
@@ -88,7 +88,7 @@ Mint body:
|
|
|
88
88
|
|
|
89
89
|
Tool calls are additionally gated by each tool's security metadata. Scope alone is not the only control.
|
|
90
90
|
|
|
91
|
-
Runtime keys may bind a tool profile. A run-scope key with profile `
|
|
91
|
+
Runtime keys may bind a tool profile. A run-scope key with profile `bookkeeping-tracking` can update todos and notes but cannot expose or execute filesystem/search/shell tools.
|
|
92
92
|
|
|
93
93
|
## Request Header
|
|
94
94
|
|
|
@@ -47,8 +47,8 @@ For bookkeeping integrations, prefer direct calls instead of `/v1/run`:
|
|
|
47
47
|
```bash
|
|
48
48
|
curl -s -X POST "$OMNIUS/v1/tools/todo_write/call" \
|
|
49
49
|
-H 'content-type: application/json' \
|
|
50
|
-
-H 'x-omnius-session-id:
|
|
51
|
-
-d '{"profile":"
|
|
50
|
+
-H 'x-omnius-session-id: tracking-turn-123' \
|
|
51
|
+
-d '{"profile":"bookkeeping-tracking","args":{"todos":[{"content":"Create report","status":"in_progress"}]}}'
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
## Abort
|
|
@@ -39,7 +39,7 @@ Filters include:
|
|
|
39
39
|
?scope=read|run|admin
|
|
40
40
|
?risk=low|medium|high|critical
|
|
41
41
|
?limit=200&offset=0
|
|
42
|
-
?profile=
|
|
42
|
+
?profile=bookkeeping-tracking
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Profiles can also be selected with `X-Tool-Profile`. Named profiles resolve in this order: built-in preset, `{working_dir}/.omnius/profiles/{name}.json`, then `~/.omnius/profiles/{name}.json`. Missing profiles fail closed.
|
|
@@ -50,10 +50,10 @@ Profiles can also be selected with `X-Tool-Profile`. Named profiles resolve in t
|
|
|
50
50
|
|
|
51
51
|
```json
|
|
52
52
|
{
|
|
53
|
-
"session_id": "
|
|
53
|
+
"session_id": "tracking-turn-123",
|
|
54
54
|
"args": {},
|
|
55
55
|
"working_dir": "/path/to/repo",
|
|
56
|
-
"profile": "
|
|
56
|
+
"profile": "bookkeeping-tracking"
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
59
|
|
|
@@ -66,8 +66,8 @@ Bookkeeping tools are direct-callable and do not require a model run:
|
|
|
66
66
|
```bash
|
|
67
67
|
curl -s -X POST "$OMNIUS/v1/tools/todo_write/call" \
|
|
68
68
|
-H 'content-type: application/json' \
|
|
69
|
-
-H 'x-omnius-session-id:
|
|
70
|
-
-d '{"profile":"
|
|
69
|
+
-H 'x-omnius-session-id: tracking-turn-123' \
|
|
70
|
+
-d '{"profile":"bookkeeping-tracking","args":{"todos":[{"content":"Create report","status":"in_progress"}]}}'
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Use `todo_write`, `todo_read`, `working_notes`, and `task_complete` this way for deterministic tracking. `task_complete` on this endpoint is only a bookkeeping boundary; `/v1/runs/{id}` remains the canonical run terminal state.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.199",
|
|
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.199",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED