omnius 1.0.618 → 1.0.620

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.
@@ -61,6 +61,17 @@ WINDOW_SECONDS = 8.0
61
61
  # HuggingFace model identifier
62
62
  MODEL_ID = "nvidia/nemotron-speech-streaming-en-0.6b"
63
63
 
64
+ # All managed ASR weights live outside the npm package so upgrades do not
65
+ # invalidate an already-pulled model. HuggingFace honors HF_HOME for both the
66
+ # NeMo and transformers loaders below.
67
+ MODEL_CACHE_ROOT = Path(
68
+ os.environ.get(
69
+ "OMNIUS_ASR_MODEL_DIR",
70
+ str(Path.home() / ".omnius" / "models" / "asr" / "nemotron-streaming"),
71
+ )
72
+ ).expanduser()
73
+ os.environ.setdefault("HF_HOME", str(MODEL_CACHE_ROOT))
74
+
64
75
  # ---------------------------------------------------------------------------
65
76
  # Output helpers (JSON lines to stdout)
66
77
  # ---------------------------------------------------------------------------
@@ -81,12 +92,42 @@ def emit_error(msg: str):
81
92
  def emit_transcript(text: str, is_final: bool = False, backend: str = "nemotron"):
82
93
  emit({"type": "transcript", "text": text, "isFinal": is_final, "backend": backend})
83
94
 
95
+
96
+ def asr_cpu_allowed() -> bool:
97
+ return os.environ.get("OMNIUS_ASR_ALLOW_CPU", "").strip().lower() in ("1", "true", "yes", "on")
98
+
99
+
100
+ def select_asr_device() -> str:
101
+ """Select CUDA whenever it is present; never silently retry on CPU."""
102
+ import torch
103
+
104
+ if torch.cuda.is_available() and torch.cuda.device_count() > 0:
105
+ raw_index = os.environ.get("OMNIUS_ASR_CUDA_DEVICE", "0").strip() or "0"
106
+ try:
107
+ index = int(raw_index)
108
+ except ValueError as error:
109
+ raise RuntimeError(f"Invalid OMNIUS_ASR_CUDA_DEVICE={raw_index!r}") from error
110
+ if index < 0 or index >= torch.cuda.device_count():
111
+ raise RuntimeError(f"OMNIUS_ASR_CUDA_DEVICE={index} is outside CUDA device range 0..{torch.cuda.device_count() - 1}")
112
+ torch.cuda.set_device(index)
113
+ return f"cuda:{index}"
114
+ if asr_cpu_allowed():
115
+ return "cpu"
116
+ cuda_version = getattr(getattr(torch, "version", None), "cuda", None)
117
+ raise RuntimeError(
118
+ f"CUDA-only ASR is enabled but PyTorch cannot use CUDA (torch.version.cuda={cuda_version}, "
119
+ f"device_count={torch.cuda.device_count()}). Set OMNIUS_ASR_ALLOW_CPU=1 only for an explicit emergency fallback."
120
+ )
121
+
84
122
  # ---------------------------------------------------------------------------
85
123
  # Venv bootstrap (same pattern as live-whisper.py)
86
124
  # ---------------------------------------------------------------------------
87
125
 
88
126
  def _in_venv() -> bool:
89
- return sys.prefix != sys.base_prefix and str(SCRIPT_DIR) in sys.prefix
127
+ # Omnius launches this worker from its managed CUDA Python environment.
128
+ # Requiring the script directory here used to create a second, CPU-prone
129
+ # venv beside the npm package on every Jetson install.
130
+ return sys.prefix != sys.base_prefix
90
131
 
91
132
 
92
133
  def _ensure_venv():
@@ -125,7 +166,7 @@ def _ensure_deps():
125
166
  emit_status(f"Installing core deps: {', '.join(need)}...")
126
167
  try:
127
168
  subprocess.check_call(
128
- [str(PIP), "install", *need],
169
+ [sys.executable, "-m", "pip", "install", *need],
129
170
  stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,
130
171
  )
131
172
  except subprocess.CalledProcessError as e:
@@ -144,7 +185,7 @@ def _ensure_deps():
144
185
  emit_status("Installing nemo_toolkit[asr] (large — may take a few minutes)...")
145
186
  try:
146
187
  subprocess.check_call(
147
- [str(PIP), "install", "nemo_toolkit[asr]"],
188
+ [sys.executable, "-m", "pip", "install", "nemo_toolkit[asr]"],
148
189
  stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,
149
190
  timeout=600,
150
191
  )
@@ -175,40 +216,22 @@ import numpy as np # noqa: E402
175
216
  # Backend loaders
176
217
  # ---------------------------------------------------------------------------
177
218
 
178
- def _load_nemo_model(model_id: str = MODEL_ID, force_cpu: bool = False):
179
- """Try to load via NeMo toolkit. Returns (model, device) or (None, None).
180
-
181
- Handles the "cuDNN not compatible with SM < 7.5" error by retrying
182
- on CPU. This is the common failure mode on older NVIDIA GPUs where
183
- the installed torch has a newer cuDNN than the hardware supports.
184
- """
185
- # If caller asked for CPU explicitly, hide the GPU from torch before
186
- # importing anything that might touch CUDA.
187
- if force_cpu:
188
- os.environ["CUDA_VISIBLE_DEVICES"] = ""
219
+ def _load_nemo_model(model_id: str = MODEL_ID):
220
+ """Load NeMo on the selected CUDA device, with no implicit CPU retry."""
189
221
  try:
190
222
  import nemo.collections.asr as nemo_asr
191
223
  import torch
192
224
  except ImportError:
193
225
  return (None, None)
194
226
  try:
227
+ device = select_asr_device()
195
228
  emit_status(f"Loading NeMo model {model_id}...")
196
229
  model = nemo_asr.models.ASRModel.from_pretrained(model_id)
197
230
  model.eval()
198
- # Force CPU to avoid cuDNN version mismatches on older GPUs
199
- if force_cpu or not torch.cuda.is_available():
200
- try:
201
- model = model.cpu()
202
- except Exception:
203
- pass
204
- return (model, "cpu" if (force_cpu or not torch.cuda.is_available()) else "cuda")
231
+ model = model.to(torch.device(device))
232
+ return (model, device)
205
233
  except Exception as e:
206
- msg = str(e)
207
- emit_status(f"NeMo load failed: {msg[:200]}")
208
- # Retry on CPU if the error looks like a cuDNN / device compat issue
209
- if not force_cpu and any(k in msg for k in ("cuDNN", "SM <", "CUDA", "device side")):
210
- emit_status("Retrying NeMo load on CPU only...")
211
- return _load_nemo_model(model_id, force_cpu=True)
234
+ emit_status(f"NeMo load failed: {str(e)[:200]}")
212
235
  return (None, None)
213
236
 
214
237
 
@@ -220,13 +243,8 @@ def _load_transformers_model(model_id: str = MODEL_ID):
220
243
  return None
221
244
  try:
222
245
  emit_status(f"Loading transformers pipeline for {model_id}...")
223
- device = -1
224
- try:
225
- import torch
226
- if torch.cuda.is_available():
227
- device = 0
228
- except ImportError:
229
- pass
246
+ selected = select_asr_device()
247
+ device = int(selected.split(":", 1)[1]) if selected.startswith("cuda:") else -1
230
248
  pipe = pipeline(
231
249
  task="automatic-speech-recognition",
232
250
  model=model_id,
@@ -329,7 +347,7 @@ def _transcribe_buffer_transformers(pipe, audio: np.ndarray) -> str:
329
347
  # File transcription mode (single-shot)
330
348
  # ---------------------------------------------------------------------------
331
349
 
332
- def transcribe_file(path: str, language: str = "en") -> int:
350
+ def transcribe_file(path: str, language: str = "en", model_id: str = MODEL_ID) -> int:
333
351
  """Single-file transcription — reads a WAV, prints one transcript
334
352
  JSON line, exits. Used by AsrListenTool's file path. Exit code 0
335
353
  on success, 1 on failure."""
@@ -348,16 +366,17 @@ def transcribe_file(path: str, language: str = "en") -> int:
348
366
  emit_error(f"Failed to load audio file {path}: {e}")
349
367
  return 1
350
368
 
351
- (model, device) = _load_nemo_model()
369
+ (model, device) = _load_nemo_model(model_id)
352
370
  backend = "nemo"
353
371
  if model is None:
354
- model = _load_transformers_model()
372
+ device = select_asr_device()
373
+ model = _load_transformers_model(model_id)
355
374
  backend = "transformers"
356
375
  if model is None:
357
376
  emit_error("No nemotron backend available (tried NeMo + transformers)")
358
377
  return 1
359
378
 
360
- emit({"type": "ready", "backend": backend, "device": device or "cpu"})
379
+ emit({"type": "ready", "backend": backend, "device": device or "cpu", "cuda": str(device).startswith("cuda")})
361
380
 
362
381
  t0 = time.time()
363
382
  if backend == "nemo":
@@ -463,14 +482,28 @@ def main():
463
482
  parser.add_argument("--window-seconds", type=float, default=WINDOW_SECONDS, help="Sliding window size")
464
483
  parser.add_argument("--stdin", action="store_true", help="Explicit stdin mode (default when no --file)")
465
484
  parser.add_argument("--check", action="store_true", help="Just verify the script parses + imports; no model load")
485
+ parser.add_argument("--setup", action="store_true", help="Pull and validate the selected model on the selected device, then exit")
466
486
  args = parser.parse_args()
467
487
 
468
488
  if args.check:
469
489
  emit({"type": "check", "ok": True, "script": str(Path(__file__).resolve())})
470
490
  return 0
471
491
 
492
+ if args.setup:
493
+ model, device = _load_nemo_model(args.model)
494
+ backend = "nemo"
495
+ if model is None:
496
+ device = select_asr_device()
497
+ model = _load_transformers_model(args.model)
498
+ backend = "transformers"
499
+ if model is None:
500
+ emit_error("No CUDA Nemotron backend available (tried NeMo + transformers)")
501
+ return 1
502
+ emit({"type": "ready", "backend": backend, "device": device, "cuda": str(device).startswith("cuda"), "model": args.model})
503
+ return 0
504
+
472
505
  if args.file:
473
- return transcribe_file(args.file, args.language)
506
+ return transcribe_file(args.file, args.language, args.model)
474
507
  return stream_stdin(args)
475
508
 
476
509
 
@@ -59,6 +59,14 @@ BLOCK_SECONDS = 0.2
59
59
  BLOCK_SAMPLES = int(SAMPLE_RATE * BLOCK_SECONDS)
60
60
 
61
61
 
62
+ def whisper_model_dir() -> Path:
63
+ """Use Omnius' durable model store instead of a package-local cache."""
64
+ configured = os.environ.get("OMNIUS_ASR_MODEL_DIR", "").strip()
65
+ if configured:
66
+ return Path(configured).expanduser()
67
+ return Path.home() / ".omnius" / "models" / "asr" / "openai-whisper"
68
+
69
+
62
70
  def env_float(name: str, default: float) -> float:
63
71
  raw = os.environ.get(name, "").strip()
64
72
  if not raw:
@@ -496,7 +504,9 @@ def main():
496
504
  device = select_whisper_device()
497
505
  emit_status(f"Loading Whisper {args.model} model on {device}...")
498
506
  try:
499
- model = whisper.load_model(args.model, device=device)
507
+ model_dir = whisper_model_dir()
508
+ model_dir.mkdir(parents=True, exist_ok=True)
509
+ model = whisper.load_model(args.model, device=device, download_root=str(model_dir))
500
510
  except Exception as e:
501
511
  if str(device).startswith("cuda"):
502
512
  emit_error(f"Failed to load model on {device}; refusing CPU fallback because CUDA is available: {e}")
@@ -511,7 +521,11 @@ def main():
511
521
  if consensus_name not in ("off", "none", "", args.model):
512
522
  emit_status(f"Loading consensus Whisper {consensus_name} model on {device}...")
513
523
  try:
514
- consensus_model = whisper.load_model(consensus_name, device=device)
524
+ consensus_model = whisper.load_model(
525
+ consensus_name,
526
+ device=device,
527
+ download_root=str(whisper_model_dir()),
528
+ )
515
529
  except Exception as e:
516
530
  emit_status(f"Consensus model unavailable ({e}); running single-model.")
517
531
  consensus_model = None
@@ -293353,7 +293353,6 @@ var MM_INDEX = join9(MM_DIR, "index.json");
293353
293353
  // packages/execution/dist/asr/registry.js
293354
293354
  var VIBEVOICE_ASR_MODEL_REVISION = "d0c9efdb8d614685062c04425d91e01b6f37d944";
293355
293355
  var VIBEVOICE_ASR_WEIGHTS_BYTES = 17348198410;
293356
- var NEMOTRON_DISABLED_REASON = "Nemotron is catalogued but its legacy self-installing worker is disabled until it is migrated to the managed fail-closed runtime.";
293357
293356
  var whisperCapabilities = Object.freeze({
293358
293357
  file: true,
293359
293358
  pcmStream: true,
@@ -293377,9 +293376,9 @@ function whisperModel(engineId, id, label) {
293377
293376
  languages: ["multilingual"],
293378
293377
  capabilities: whisperCapabilities,
293379
293378
  resources: {
293380
- cpuSupported: engineId === "transcribe-cli",
293379
+ cpuSupported: false,
293381
293380
  architectures: ["x64", "arm64"],
293382
- notes: engineId === "transcribe-cli" ? ["Managed transcribe-cli runtime; implementation may use faster-whisper or ONNX."] : ["CUDA is required by Omnius unless an explicit local override is configured."]
293381
+ notes: ["CUDA is required by Omnius unless an explicit local override is configured."]
293383
293382
  }
293384
293383
  };
293385
293384
  }
@@ -293395,15 +293394,6 @@ var ASR_ENGINES = Object.freeze([
293395
293394
  setupMode: "managed",
293396
293395
  models: whisperModels("openai-whisper")
293397
293396
  },
293398
- {
293399
- id: "transcribe-cli",
293400
- label: "transcribe-cli",
293401
- detail: "Managed faster-whisper/ONNX bridge for live and file transcription",
293402
- provider: "transcribe-cli",
293403
- runtime: "node",
293404
- setupMode: "managed",
293405
- models: whisperModels("transcribe-cli")
293406
- },
293407
293397
  {
293408
293398
  id: "nemotron-streaming",
293409
293399
  label: "NVIDIA Nemotron Speech Streaming",
@@ -293411,8 +293401,6 @@ var ASR_ENGINES = Object.freeze([
293411
293401
  provider: "NVIDIA",
293412
293402
  runtime: "python",
293413
293403
  setupMode: "managed",
293414
- availability: "disabled",
293415
- unavailableReason: NEMOTRON_DISABLED_REASON,
293416
293404
  models: [
293417
293405
  {
293418
293406
  id: "nemotron-speech-streaming-en-0.6b",
@@ -3249,6 +3249,198 @@
3249
3249
  "packages/cli/src/api/openapi.ts"
3250
3250
  ]
3251
3251
  },
3252
+ {
3253
+ "id": "api.v1-asr-engines-engine-id-models-model-id-deploy",
3254
+ "kind": "api",
3255
+ "title": "/v1/asr/engines/{engineId}/models/{modelId}/deploy",
3256
+ "summary": "Pull, select, and activate one exact ASR model",
3257
+ "aliases": [
3258
+ "/v1/asr/engines/{engineId}/models/{modelId}/deploy"
3259
+ ],
3260
+ "keywords": [
3261
+ "rest",
3262
+ "openapi",
3263
+ "POST",
3264
+ "ASR",
3265
+ "v1",
3266
+ "asr",
3267
+ "engines",
3268
+ "{engineId}",
3269
+ "models",
3270
+ "{modelId}",
3271
+ "deploy"
3272
+ ],
3273
+ "maturity": "stable",
3274
+ "layer": "interface",
3275
+ "audiences": [
3276
+ "integrator",
3277
+ "service-agent",
3278
+ "coding-agent"
3279
+ ],
3280
+ "interfaces": [
3281
+ {
3282
+ "type": "rest",
3283
+ "target": "POST /v1/asr/engines/{engineId}/models/{modelId}/deploy"
3284
+ },
3285
+ {
3286
+ "type": "openapi",
3287
+ "target": "/openapi.json"
3288
+ }
3289
+ ],
3290
+ "references": [
3291
+ {
3292
+ "type": "source",
3293
+ "target": "packages/cli/src/api/openapi.ts",
3294
+ "relation": "openapi-source"
3295
+ },
3296
+ {
3297
+ "type": "documentation",
3298
+ "target": "docs/reference/rest-api.md",
3299
+ "relation": "endpoint-inventory"
3300
+ }
3301
+ ],
3302
+ "methods": [
3303
+ "POST"
3304
+ ],
3305
+ "tags": [
3306
+ "ASR"
3307
+ ],
3308
+ "operations": {
3309
+ "post": {
3310
+ "summary": "Pull, select, and activate one exact ASR model",
3311
+ "tags": [
3312
+ "ASR"
3313
+ ],
3314
+ "description": "Optional body: {device}. Persists the selection after the managed runtime and weights are ready.",
3315
+ "parameters": [
3316
+ {
3317
+ "name": "engineId",
3318
+ "in": "path",
3319
+ "required": true,
3320
+ "schema": {
3321
+ "type": "string"
3322
+ }
3323
+ },
3324
+ {
3325
+ "name": "modelId",
3326
+ "in": "path",
3327
+ "required": true,
3328
+ "schema": {
3329
+ "type": "string"
3330
+ }
3331
+ }
3332
+ ],
3333
+ "responses": {
3334
+ "200": {
3335
+ "description": "Model deployed and selected"
3336
+ },
3337
+ "500": {
3338
+ "description": "Deploy or CUDA validation failed"
3339
+ }
3340
+ }
3341
+ }
3342
+ },
3343
+ "source_of_truth": [
3344
+ "GET /openapi.json",
3345
+ "packages/cli/src/api/openapi.ts"
3346
+ ]
3347
+ },
3348
+ {
3349
+ "id": "api.v1-asr-engines-engine-id-models-model-id-pull",
3350
+ "kind": "api",
3351
+ "title": "/v1/asr/engines/{engineId}/models/{modelId}/pull",
3352
+ "summary": "Pull one exact ASR model and validate its managed runtime",
3353
+ "aliases": [
3354
+ "/v1/asr/engines/{engineId}/models/{modelId}/pull"
3355
+ ],
3356
+ "keywords": [
3357
+ "rest",
3358
+ "openapi",
3359
+ "POST",
3360
+ "ASR",
3361
+ "v1",
3362
+ "asr",
3363
+ "engines",
3364
+ "{engineId}",
3365
+ "models",
3366
+ "{modelId}",
3367
+ "pull"
3368
+ ],
3369
+ "maturity": "stable",
3370
+ "layer": "interface",
3371
+ "audiences": [
3372
+ "integrator",
3373
+ "service-agent",
3374
+ "coding-agent"
3375
+ ],
3376
+ "interfaces": [
3377
+ {
3378
+ "type": "rest",
3379
+ "target": "POST /v1/asr/engines/{engineId}/models/{modelId}/pull"
3380
+ },
3381
+ {
3382
+ "type": "openapi",
3383
+ "target": "/openapi.json"
3384
+ }
3385
+ ],
3386
+ "references": [
3387
+ {
3388
+ "type": "source",
3389
+ "target": "packages/cli/src/api/openapi.ts",
3390
+ "relation": "openapi-source"
3391
+ },
3392
+ {
3393
+ "type": "documentation",
3394
+ "target": "docs/reference/rest-api.md",
3395
+ "relation": "endpoint-inventory"
3396
+ }
3397
+ ],
3398
+ "methods": [
3399
+ "POST"
3400
+ ],
3401
+ "tags": [
3402
+ "ASR"
3403
+ ],
3404
+ "operations": {
3405
+ "post": {
3406
+ "summary": "Pull one exact ASR model and validate its managed runtime",
3407
+ "tags": [
3408
+ "ASR"
3409
+ ],
3410
+ "description": "Optional body: {device}. Downloads model weights into Omnius-managed storage and verifies CUDA placement for Whisper and Nemotron.",
3411
+ "parameters": [
3412
+ {
3413
+ "name": "engineId",
3414
+ "in": "path",
3415
+ "required": true,
3416
+ "schema": {
3417
+ "type": "string"
3418
+ }
3419
+ },
3420
+ {
3421
+ "name": "modelId",
3422
+ "in": "path",
3423
+ "required": true,
3424
+ "schema": {
3425
+ "type": "string"
3426
+ }
3427
+ }
3428
+ ],
3429
+ "responses": {
3430
+ "200": {
3431
+ "description": "Weights are ready"
3432
+ },
3433
+ "500": {
3434
+ "description": "Runtime, download, or CUDA validation failed"
3435
+ }
3436
+ }
3437
+ }
3438
+ },
3439
+ "source_of_truth": [
3440
+ "GET /openapi.json",
3441
+ "packages/cli/src/api/openapi.ts"
3442
+ ]
3443
+ },
3252
3444
  {
3253
3445
  "id": "api.v1-asr-engines-engine-id-setup",
3254
3446
  "kind": "api",
@@ -3309,7 +3501,7 @@
3309
3501
  "tags": [
3310
3502
  "ASR"
3311
3503
  ],
3312
- "description": "Currently implemented for vibevoice-transformers. The exact microsoft/VibeVoice-ASR revision and tokenizer snapshot are stored under the unified Omnius ASR model/runtime directories; model weights are never bundled into npm.",
3504
+ "description": "Body: {modelId?, device?}. Installs the managed runtime and pulls the requested model. Whisper and Nemotron loads validate their selected CUDA device; VibeVoice stores its pinned model and tokenizer snapshot under Omnius' ASR runtime directories.",
3313
3505
  "parameters": [
3314
3506
  {
3315
3507
  "name": "engineId",
@@ -3413,7 +3605,7 @@
3413
3605
  "tags": [
3414
3606
  "ASR"
3415
3607
  ],
3416
- "description": "Body: {engineId, modelId?, setup?, device?}. Selection is validated against the registry. VibeVoice activation is CUDA-only and fail-closed; setup=true installs the pinned runtime and exact weights before activation. Hardware evidence uses nvidia-smi on discrete Linux and NVIDIA's documented tegrastats plus a CUDA Torch property probe on Jetson/L4T.",
3608
+ "description": "Body: {engineId, modelId?, setup?, device?}. Selection is validated against the registry. setup=true pulls the exact managed model and verifies CUDA placement before activation. Hardware evidence uses nvidia-smi on discrete Linux and NVIDIA's documented tegrastats plus a CUDA Torch property probe on Jetson/L4T.",
3417
3609
  "responses": {
3418
3610
  "200": {
3419
3611
  "description": "Exact selection activated"
package/docs/DISCOVERY.md CHANGED
@@ -88,6 +88,8 @@ Daemon equivalents are `GET /v1/discovery/bootstrap`, `GET /v1/discovery?q=<inte
88
88
  | `api.v1-aiwg-use` | /v1/aiwg/use | AIWG cascade activation bundle (aiwg use all equivalent, model-tier sized) |
89
89
  | `api.v1-asr-activate` | /v1/asr/activate | Activate and persist an exact ASR engine/model |
90
90
  | `api.v1-asr-engines` | /v1/asr/engines | List all ASR engines, models, capabilities, resource requirements, readiness, and active selection |
91
+ | `api.v1-asr-engines-engine-id-models-model-id-deploy` | /v1/asr/engines/{engineId}/models/{modelId}/deploy | Pull, select, and activate one exact ASR model |
92
+ | `api.v1-asr-engines-engine-id-models-model-id-pull` | /v1/asr/engines/{engineId}/models/{modelId}/pull | Pull one exact ASR model and validate its managed runtime |
91
93
  | `api.v1-asr-engines-engine-id-setup` | /v1/asr/engines/{engineId}/setup | Install a managed ASR runtime and its pinned weights |
92
94
  | `api.v1-asr-selection` | /v1/asr/selection | Read the selected ASR engine/model; Persist and activate an exact ASR selection |
93
95
  | `api.v1-asr-status` | /v1/asr/status | Read the selected ASR engine/model and runtime status |
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.618",
3
+ "version": "1.0.620",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.618",
9
+ "version": "1.0.620",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.618",
3
+ "version": "1.0.620",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/library.js",