omnius 1.0.639 → 1.0.641

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.
@@ -8,16 +8,65 @@ stdout: JSON {"text": "...", "duration": null, "segments": []}
8
8
 
9
9
  ASR is GPU-first: CPU fallback is refused unless OMNIUS_ASR_ALLOW_CPU=1.
10
10
  """
11
- import sys, os, json, warnings
11
+ import sys, os, json, math, struct, warnings, wave
12
12
 
13
13
  warnings.filterwarnings("ignore")
14
14
  os.environ.setdefault("PYTHONWARNINGS", "ignore")
15
15
 
16
- try:
17
- import whisper
18
- except Exception as e:
19
- print(json.dumps({"error": "deps_missing", "message": str(e)}))
20
- sys.exit(0)
16
+ PCM16_SILENCE_MAX_PEAK = 4
17
+ PCM16_SILENCE_MAX_RMS = 1.0
18
+ PCM16_ACTIVE_SAMPLE_THRESHOLD = 8
19
+
20
+
21
+ def exact_pcm16_silence(path):
22
+ """Return typed no-speech evidence for exact PCM16/16k/mono WAV only.
23
+
24
+ This is intentionally not VAD. It reads user bytes but never rewrites,
25
+ normalizes, decodes another media format, or instantiates Whisper.
26
+ """
27
+ try:
28
+ with wave.open(path, "rb") as wav:
29
+ if (
30
+ wav.getcomptype() != "NONE"
31
+ or wav.getnchannels() != 1
32
+ or wav.getsampwidth() != 2
33
+ or wav.getframerate() != 16000
34
+ ):
35
+ return None
36
+ frames = wav.readframes(wav.getnframes())
37
+ except (wave.Error, OSError, EOFError):
38
+ return None
39
+ sample_count = len(frames) // 2
40
+ if sample_count == 0:
41
+ metrics = {
42
+ "sampleRateHz": 16000, "channels": 1, "bitsPerSample": 16,
43
+ "sampleCount": 0, "durationMs": 0.0, "peakPcm16": 0,
44
+ "rmsPcm16": 0.0, "activeSampleCount": 0, "activeSampleRatio": 0.0,
45
+ }
46
+ else:
47
+ samples = struct.iter_unpack("<h", frames[: sample_count * 2])
48
+ total_squares = 0
49
+ peak = 0
50
+ active = 0
51
+ for (sample,) in samples:
52
+ magnitude = abs(sample)
53
+ total_squares += sample * sample
54
+ peak = max(peak, magnitude)
55
+ if magnitude >= PCM16_ACTIVE_SAMPLE_THRESHOLD:
56
+ active += 1
57
+ metrics = {
58
+ "sampleRateHz": 16000, "channels": 1, "bitsPerSample": 16,
59
+ "sampleCount": sample_count, "durationMs": sample_count / 16.0,
60
+ "peakPcm16": peak, "rmsPcm16": math.sqrt(total_squares / sample_count),
61
+ "activeSampleCount": active, "activeSampleRatio": active / sample_count,
62
+ }
63
+ if (
64
+ metrics["peakPcm16"] <= PCM16_SILENCE_MAX_PEAK
65
+ and metrics["rmsPcm16"] <= PCM16_SILENCE_MAX_RMS
66
+ and metrics["activeSampleCount"] == 0
67
+ ):
68
+ return {"kind": "no_speech", "reason": "digital_silence", "text": "", "signal": metrics}
69
+ return None
21
70
 
22
71
 
23
72
  def main() -> None:
@@ -33,8 +82,14 @@ def main() -> None:
33
82
  print(json.dumps({"error": "file_not_found", "path": path or ""}))
34
83
  return
35
84
 
85
+ no_speech = exact_pcm16_silence(path)
86
+ if no_speech is not None:
87
+ print(json.dumps({**no_speech, "duration": no_speech["signal"]["durationMs"] / 1000.0, "segments": []}))
88
+ return
89
+
36
90
  model_name = data.get("model") or "tiny"
37
91
  try:
92
+ import whisper
38
93
  device = os.environ.get("OMNIUS_ASR_DEVICE", "cuda").strip().lower() or "cuda"
39
94
  allow_cpu = os.environ.get("OMNIUS_ASR_ALLOW_CPU", "").strip().lower() in ("1", "true", "yes", "on")
40
95
  if device == "auto":
@@ -293080,7 +293080,6 @@ var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
293080
293080
 
293081
293081
  // packages/execution/dist/tools/ocr-image-advanced.js
293082
293082
  init_process_async();
293083
- var OCR_PIPELINE_TIMEOUT_MS = 5 * 6e4;
293084
293083
 
293085
293084
  // packages/execution/dist/tools/browser-action.js
293086
293085
  init_process_lifecycle();
@@ -4171,7 +4171,7 @@
4171
4171
  ],
4172
4172
  "responses": {
4173
4173
  "200": {
4174
- "description": "Transcription with actual engine/model identity and supported structured metadata"
4174
+ "description": "Transcription with actual engine/model identity; exact digital PCM silence returns text='' plus typed noSpeech evidence without model inference"
4175
4175
  },
4176
4176
  "400": {
4177
4177
  "description": "Empty or tiny audio"
@@ -5399,7 +5399,7 @@
5399
5399
  "tags": [
5400
5400
  "Audio"
5401
5401
  ],
5402
- "description": "Admin-only. Requires kind=acoustic|speaker|semantic in the query (canonical) or JSON body. acoustic reuses the pinned JetPack YAMNet/TensorRT setup; speaker installs the isolated CPU-only WeSpeaker CAM++ ONNX Runtime and pinned model, then installs only checksummed wheels into ~/.omnius/runtimes/audio/speaker/venv: CPython 3.10/aarch64 Torchaudio 2.2.0 and the self-contained typing_extensions support dependency, each with --no-deps/--no-index. It retains --system-site-packages and links the selected OMNIUS_AUDIO_PYTHON JetPack Torch 2.2/CUDA 12.2 provider without writing to it; setup proves the Torch/Torchaudio ABI and CPU kaldi.fbank before readiness. An operator may replace the Torchaudio wheel only by supplying both OMNIUS_SPEAKER_TORCHAUDIO_WHEEL and OMNIUS_SPEAKER_TORCHAUDIO_WHEEL_SHA256. semantic installs the isolated JetPack CUDA CLAP dependencies and pinned model. This is the only REST operation allowed to provision. It activates and warms only the requested role worker; no role is substituted for another.",
5402
+ "description": "Admin-only. Requires kind=acoustic|speaker|semantic in the query (canonical) or JSON body. acoustic reuses the pinned JetPack YAMNet/TensorRT setup; speaker creates a private CPython 3.10 CPU-only WeSpeaker CAM++ venv, installs only checksum-pinned NumPy, ONNX Runtime, and its locked CPU support wheels with --no-deps/--no-index, then downloads the pinned model. Its 80-bin Kaldi-compatible NumPy fbank is validated with a versioned cross-platform numeric-invariant probe before readiness. The speaker path never imports, links, replaces, or otherwise depends on JetPack Torch/Torchaudio, so an incompatible generic Torchaudio wheel cannot affect CUDA-enabled Egg Torch. semantic installs the isolated JetPack CUDA CLAP dependencies and pinned model. This is the only REST operation allowed to provision. It activates and warms only the requested role worker; no role is substituted for another.",
5403
5403
  "parameters": [
5404
5404
  {
5405
5405
  "name": "kind",
@@ -6070,7 +6070,7 @@
6070
6070
  "$ref": "#/components/parameters/MinimumOmniusVersion"
6071
6071
  }
6072
6072
  ],
6073
- "description": "Standard OpenAI chat-completion proxy by default. Set agent_loop=true to enter a synchronous server-side loop that auto-executes daemon tools (web_search, web_fetch, file_read, ocr, etc.) and re-prompts the model — collapsing N round-trips into 1. include_daemon_tools=['read','run'] auto-merges daemon tools matching those scopes into the offered tools[]. timeout_s overrides OMNIUS_BACKEND_TIMEOUT_S (default 120s, max 1h). prompt_template='factual-first' prepends a web_search-first policy. SSE streaming honors tool_calls in delta as standard OpenAI shape: delta.tool_calls=[{id,type:'function',index,function:{name,arguments:<JSON-string>}}]. parallel_tool_calls is forwarded to the backend.",
6073
+ "description": "Standard OpenAI chat-completion proxy by default. Set agent_loop=true to enter a bounded synchronous server-side loop that auto-executes selected daemon tools and re-prompts the model. Ollama targets use native /api/chat tool messages. timeout_s bounds each backend call; agent_timeout_s bounds the whole loop (default 45s, max 600s). daemon_tool_names explicitly limits the offered catalog; factual-first implicitly limits it to web_search/web_fetch when no names are supplied. Identical repeated calls fail with HTTP 508 instead of looping. SSE streaming outside agent_loop honors OpenAI tool_calls deltas.",
6074
6074
  "requestBody": {
6075
6075
  "required": true,
6076
6076
  "content": {
@@ -6140,7 +6140,28 @@
6140
6140
  "admin"
6141
6141
  ]
6142
6142
  },
6143
- "description": "Q3 — scopes to merge from daemon tool catalog into tools[]."
6143
+ "description": "Scopes from which Omnius may offer its bounded core daemon-tool catalog. Use daemon_tool_names to request other exact tools."
6144
+ },
6145
+ "daemon_tool_names": {
6146
+ "type": "array",
6147
+ "items": {
6148
+ "type": "string"
6149
+ },
6150
+ "description": "Optional exact allowlist of daemon tool names. Use this to keep local-model tool prompts small."
6151
+ },
6152
+ "agent_timeout_s": {
6153
+ "type": "number",
6154
+ "minimum": 5,
6155
+ "maximum": 600,
6156
+ "default": 45,
6157
+ "description": "Total server-side agent-loop deadline. Distinct from per-backend timeout_s."
6158
+ },
6159
+ "agent_max_tool_rounds": {
6160
+ "type": "integer",
6161
+ "minimum": 1,
6162
+ "maximum": 8,
6163
+ "default": 1,
6164
+ "description": "Maximum daemon-tool planning rounds. The default executes one tool round, then removes daemon schemas for lower-latency final synthesis."
6144
6165
  },
6145
6166
  "max_turns": {
6146
6167
  "type": "integer",
@@ -6160,7 +6181,7 @@
6160
6181
  },
6161
6182
  "responses": {
6162
6183
  "200": {
6163
- "description": "OpenAI chat.completion shape, SSE if stream=true. agent_loop responses include _agent_loop:{turns,log,done,reason}."
6184
+ "description": "OpenAI chat.completion shape, SSE if stream=true. agent_loop responses include _agent_loop:{turns,log,done,reason,elapsed_ms,backend_transport}."
6164
6185
  },
6165
6186
  "400": {
6166
6187
  "description": "Invalid request",
@@ -6231,6 +6252,12 @@
6231
6252
  }
6232
6253
  }
6233
6254
  }
6255
+ },
6256
+ "504": {
6257
+ "description": "Backend round or total agent-loop deadline expired"
6258
+ },
6259
+ "508": {
6260
+ "description": "The model repeated an identical daemon tool call"
6234
6261
  }
6235
6262
  }
6236
6263
  }
@@ -18540,7 +18567,7 @@
18540
18567
  "tags": [
18541
18568
  "Voice"
18542
18569
  ],
18543
- "description": "Returns synthesized audio and automatically enables/warms the selected runtime. Format `wav` (default) ships a complete WAV with header; `pcm` ships raw Int16 LE PCM. Set model=voxtral-4b-tts-2603 and voice=<preset> for the managed CUDA Voxtral renderer; the OpenAI-compatible alias also accepts model=mistralai/Voxtral-4B-TTS-2603. Other model transactions remain serialized and restore the persistent renderer. Headers report X-Voice-Model, X-Voice-Backend, and X-Sample-Rate.",
18570
+ "description": "Returns synthesized audio and automatically enables/warms the selected runtime. An explicit model has no silent fallback. Format `wav` (default) ships a complete WAV with header; `pcm` ships raw Int16 LE PCM. Set model=voxtral-4b-tts-2603 and voice=<preset> for the managed CUDA Voxtral renderer; the OpenAI-compatible alias also accepts model=mistralai/Voxtral-4B-TTS-2603. Other model transactions remain serialized and restore the persistent renderer. Headers report X-Voice-Model, X-Voice-Backend, and X-Sample-Rate.",
18544
18571
  "responses": {
18545
18572
  "200": {
18546
18573
  "description": "Audio bytes (audio/wav or audio/L16). Headers: X-Voice-Model, X-Sample-Rate."
@@ -43,7 +43,10 @@ Important body fields:
43
43
  | `parallel_tool_calls` | boolean | Forwarded to backend |
44
44
  | `timeout_s` | number | Per-request timeout |
45
45
  | `agent_loop` | boolean | Run server-side tool loop |
46
- | `include_daemon_tools` | array | Merge daemon tools by scope: `read`, `run`, `admin` |
46
+ | `include_daemon_tools` | array | Permit the bounded core daemon-tool catalog by scope: `read`, `run`, `admin` |
47
+ | `daemon_tool_names` | array | Exact daemon-tool allowlist; recommended for local models |
48
+ | `agent_timeout_s` | number | Whole-loop deadline, default 45 seconds and maximum 600 |
49
+ | `agent_max_tool_rounds` | integer | Daemon tool rounds before forced final synthesis; default 1 |
47
50
  | `max_turns` | integer | Server-side agent loop turn cap |
48
51
  | `prompt_template` | string | Optional template such as `factual-first` |
49
52
 
@@ -126,3 +129,5 @@ For ASR/TTS systems that only need the text brain, use `/realtime` or `/v1/realt
126
129
  ## Server-Side Agent Loop
127
130
 
128
131
  `/v1/chat/completions` can run an internal tool loop when `agent_loop: true`. This lets clients collapse multiple model/tool round trips into one daemon request. Daemon tool calls execute inline; client-owned tool calls can still be yielded in OpenAI-compatible shape.
132
+
133
+ Ollama-backed loops use its native `/api/chat` tool protocol. `timeout_s` applies to each backend round, while `agent_timeout_s` bounds the complete loop and defaults to 45 seconds. The planning turn is capped at 96 output tokens. By default Omnius executes one daemon-tool round, then removes daemon schemas for the final synthesis; set `agent_max_tool_rounds` only when a workflow genuinely needs deeper tool chaining. Omnius returns a typed HTTP 504 when the total budget expires and HTTP 508 when a model repeats the same daemon tool with identical arguments. Tool results are capped at 6,000 characters before the next prompt. Without `daemon_tool_names`, Omnius offers only a compact core catalog permitted by `include_daemon_tools`; `prompt_template: "factual-first"` narrows it further to `web_search` and `web_fetch`.
@@ -115,7 +115,7 @@ pipeline payload in `result.data`.
115
115
  ```bash
116
116
  curl -sS -X POST http://127.0.0.1:11435/v1/ocr/advanced \
117
117
  -H 'content-type: application/json' \
118
- -d '{"args":{"image":"/data/invoice.png","language":"eng","psm":6},"timeout_ms":300000}'
118
+ -d '{"args":{"image":"/data/invoice.png","language":"eng","psm":6},"timeout_ms":90000}'
119
119
  ```
120
120
 
121
121
  Inference never invokes sudo, apt, pip, or venv creation. If readiness is
@@ -126,6 +126,22 @@ version results without requiring particular dpkg package names. The caller
126
126
  needs `run` scope because optional
127
127
  `output_dir`, batch, and debug modes write OCR artifacts.
128
128
 
129
+ The managed pipeline is bounded: it starts with high-yield preprocessing and
130
+ expands variants only for low-evidence or larger images. Small crops avoid the
131
+ former all-variant/all-PSM explosion. The REST default is 90 seconds (maximum
132
+ 180 seconds), while the worker has an 80-second internal deadline so it can
133
+ return diagnostics. A timeout or cancellation returns
134
+ `result.data.schema=omnius.ocr-diagnostic.v1` with code `ocr_timeout` or
135
+ `ocr_cancelled`; cancellation terminates the Python/Tesseract process group
136
+ with TERM followed by KILL.
137
+
138
+ OCR text is evidence-gated before it is returned. Strong text with adequate
139
+ confidence is accepted. An empty or tiny non-substantive result is a successful
140
+ `omnius.ocr-evidence.v1` `low_information` observation with diagnostic code
141
+ `ocr_low_information`, not a fabricated transcript. High-volume low-confidence
142
+ or symbol-heavy output is suppressed and returned as
143
+ `ocr_evidence_rejected`; its raw text is not exposed as alternate OCR evidence.
144
+
129
145
  ## TTS
130
146
 
131
147
  `POST /v1/voice/tts` returns audio bytes. `format` can be `wav` or `pcm`. `X-Sample-Rate` reports the sample rate.
@@ -251,28 +267,23 @@ startup follows `OMNIUS_AUDIO_AUTO_SETUP` for acoustic and speaker; semantic
251
267
  startup additionally requires `OMNIUS_SEMANTIC_AUDIO_AUTO_SETUP=1`.
252
268
 
253
269
  On JetPack, speaker setup deliberately leaves `OMNIUS_AUDIO_PYTHON` (including
254
- an Egg project `.venv`) unchanged. It creates
255
- `~/.omnius/runtimes/audio/speaker/venv` with `--system-site-packages`, links
256
- that selected JetPack Torch 2.2/CUDA 12.2 provider from the managed venv only,
257
- and installs the exact checksummed upstream CPython 3.10/aarch64
258
- `torchaudio-2.2.0` wheel there with `--no-deps --no-index`. It never invokes a
259
- generic Torch/Torchaudio pip resolver or changes host/Egg Torch. Before it is
260
- ready, setup proves the effective Torch/Torchaudio 2.2 ABI and runs the
261
- CPU-only `torchaudio.compliance.kaldi.fbank` 80-bin probe. If an operator needs
262
- a vendor-specific wheel, both an HTTPS/local-wheel
263
- `OMNIUS_SPEAKER_TORCHAUDIO_WHEEL` and immutable
264
- `OMNIUS_SPEAKER_TORCHAUDIO_WHEEL_SHA256` must be supplied; an incomplete or
265
- failed ABI override remains unready with a remediation error rather than
266
- falling back to generic pip.
267
-
268
- The managed speaker venv also carries the checksummed `typing_extensions`
269
- support wheel required by JetPack Torch 2.2. This matters when a project venv
270
- can import that module only from its Python user site: speaker inference keeps
271
- `PYTHONNOUSERSITE=1`, so it never borrows mutable user-site packages at runtime.
272
- The bootstrap step inspects only CPython/site-package location before this
273
- repair; the managed-venv Torch import is authoritative. If another dependency
274
- is missing, readiness and setup preserve the exact missing module name instead
275
- of incorrectly reporting that the selected JetPack Torch is invalid.
270
+ an Egg project `.venv`) unchanged. It creates a private, non-system-site
271
+ `~/.omnius/runtimes/audio/speaker/venv`, then installs only a locked,
272
+ checksum-verified CPython 3.10/aarch64 CPU dependency set: NumPy 1.26.4,
273
+ ONNX Runtime 1.17.3, and the exact CPU support wheels required by that ONNX
274
+ Runtime release. Each wheel is materialized and SHA-256 verified before the
275
+ managed venv installs it with `--no-deps --no-index`.
276
+
277
+ The worker implements the WeSpeaker CAM++ 80-bin Kaldi configuration in pure
278
+ NumPy: 25 ms / 10 ms Hamming frames, dither disabled, Kaldi pre-emphasis and
279
+ mel bank behavior, then full-clip CMN without CVN. Readiness invokes a
280
+ versioned CPU preprocessing probe. It checks the fixed Kaldi configuration,
281
+ feature shape, CMN, energy range, and expected mel-band profile with explicit
282
+ cross-platform numeric tolerances before it can report ready. The speaker path neither imports
283
+ nor links Torch or Torchaudio, so the generic `torchaudio-2.2.0` ABI mismatch
284
+ cannot bind against, replace, or otherwise affect JetPack's CUDA-enabled Egg
285
+ Torch. Inference remains install-free and network-free; failed package imports
286
+ or calibration leave the role unready with the exact probe error.
276
287
 
277
288
  The dedicated route returns typed HTTP 503 whenever its requested runtime is
278
289
  unprovisioned or unavailable: `audio_classifier_not_ready` (acoustic),
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.639",
3
+ "version": "1.0.641",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.639",
9
+ "version": "1.0.641",
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.639",
3
+ "version": "1.0.641",
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",