Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
e89d0e7
feat(audio): agent-ready stages + the audio curation agent
shubhamNvidia Aug 25, 2026
33a6e8e
fix(audio): address safe agent foundation review findings
shubhamNvidia Sep 4, 2026
90d60c3
fix(audio-agent): give composite_unrunnable a remediation hint
shubhamNvidia Sep 4, 2026
8209cca
fix(audio): three silent-wrong-data findings from the foundation review
shubhamNvidia Sep 4, 2026
2a2f37d
refactor(audio-agent): retire the duplicate task-type check
shubhamNvidia Sep 4, 2026
cc2a517
test(audio-agent): regenerate the stage compatibility baseline
shubhamNvidia Sep 4, 2026
bfd5de9
Merge branch 'main' into agent/adv
shubhamNvidia Sep 7, 2026
d3cee7b
fix(audio): three more validate-clean-then-fail findings
shubhamNvidia Sep 8, 2026
7305e54
fix(audio): harden foundation validation edge cases
shubhamNvidia Sep 9, 2026
da89c53
fix(audio-agent): distinguish manifest columns from tensors
shubhamNvidia Sep 9, 2026
afc73b3
fix(audio): avoid folder item ID collisions
shubhamNvidia Sep 9, 2026
7ba8c38
fix(audio-io): harden export and serialization boundaries
shubhamNvidia Sep 9, 2026
d45fe65
fix(audio-io): reject unsafe checkpointed writers
shubhamNvidia Sep 9, 2026
a580f67
style(audio-io): fix import order after integration
shubhamNvidia Sep 9, 2026
1853da3
fix(audio): address tagging review safety issues
shubhamNvidia Sep 9, 2026
d481b56
fix(audio): scope NeMo aligner contract writes
shubhamNvidia Sep 9, 2026
3841c63
fix(audio): normalize tagging stage contracts
shubhamNvidia Sep 9, 2026
5c4bb62
test(audio-agent): refresh tagging compatibility baseline
shubhamNvidia Sep 9, 2026
15f6321
fix(audio-alm): harden contracts and sink safety
shubhamNvidia Sep 10, 2026
7bd602b
test(audio-agent): refresh ALM compatibility baseline
shubhamNvidia Sep 10, 2026
83e9e2d
docs(audio): sync composite validation contract
shubhamNvidia Sep 10, 2026
9e8e459
fix(audio-agent): validate hidden and residency parameters
shubhamNvidia Sep 15, 2026
f2c9c37
fix(audio-agent): support conditional and nested contracts
shubhamNvidia Sep 15, 2026
8b705c3
fix(audio-metrics): harden residency and contracts
shubhamNvidia Sep 15, 2026
9c00890
fix(audio-metrics): support configurable WER timing
shubhamNvidia Sep 15, 2026
cbee81c
fix(audio-metrics): complete validation and conformance
shubhamNvidia Sep 15, 2026
1fb5576
style(audio-metrics): organize test imports
shubhamNvidia Sep 15, 2026
9e37e04
chore(audio-agent): complete metrics branch synchronization
shubhamNvidia Sep 15, 2026
e10b158
fix(audio-agent): require literal keys for generic reads
shubhamNvidia Sep 15, 2026
94052cc
test(audio-metrics): cover conditional selector failure
shubhamNvidia Sep 15, 2026
40e4ed6
fix(audio-agent): recognize conditional output keys
shubhamNvidia Sep 16, 2026
30f08d5
Merge branch 'main' into agent/adv
shubhamNvidia Sep 16, 2026
0edc5de
fix(audio-inference): harden residency and fan-out
shubhamNvidia Sep 16, 2026
f993001
test(audio-agent): refresh inference compatibility baseline
shubhamNvidia Sep 16, 2026
961301f
docs(audio-agent): sync inference capability cards
shubhamNvidia Sep 16, 2026
b3db7cc
fix(audio-agent): preserve filtering residency consistency
shubhamNvidia Sep 16, 2026
77b2dad
fix(audio-filtering): address review safety findings
shubhamNvidia Sep 16, 2026
34c12cd
test(audio-agent): sync filtering contracts and cards
shubhamNvidia Sep 16, 2026
4c27d05
fix(audio-agent): scope residency, literals, and positional compatibi…
shubhamNvidia Sep 16, 2026
077ab74
test(audio-agent): refresh baseline for positional fix
shubhamNvidia Sep 16, 2026
9c941ce
fix(audio-agent): support optional contract reads
shubhamNvidia Sep 16, 2026
d46ca6b
fix(audio-io): preserve compatibility and fallback contracts
shubhamNvidia Sep 16, 2026
ffe5ed3
fix(audio-agent): sync IO contract metadata
shubhamNvidia Sep 16, 2026
8ecbea3
style(audio-io): satisfy ruff checks
shubhamNvidia Sep 16, 2026
bb2750c
fix(audio-metrics): sync reviewed compatibility fixes
shubhamNvidia Sep 16, 2026
937bf4a
fix(audio-io): sync distinct group identities
shubhamNvidia Sep 16, 2026
ed947f6
fix(audio-alm): sync compatibility fixes
shubhamNvidia Sep 16, 2026
36cfa89
fix(audio-tagging): address re-review safety findings
shubhamNvidia Sep 16, 2026
a547e7c
fix(audio): sync safe inference behavior
shubhamNvidia Sep 16, 2026
9cc80b1
fix(audio-postprocessing): harden timestamp mapping
shubhamNvidia Sep 16, 2026
66d1f3e
fix(audio-segmentation): address agent review findings
shubhamNvidia Sep 16, 2026
393872d
fix(audio-datasets): correct agent contracts
shubhamNvidia Sep 16, 2026
62889e2
test(audio-agent): restore float waveform regression
shubhamNvidia Sep 16, 2026
9b2b26b
fix(audio-agent): plan conditional writes honestly instead of refusin…
shubhamNvidia Sep 17, 2026
d6ef69f
fix(audio): restore Prepare default output, restart-safe writers, ver…
shubhamNvidia Sep 17, 2026
504c4c3
test(audio-agent): repair drifted adv-only tests and allowlist fake s…
shubhamNvidia Sep 17, 2026
876fc19
fix(audio): keep legacy default outputs for the ALM reader and Timest…
shubhamNvidia Sep 17, 2026
1e92384
fix(audio-advanced): declare static filter contract
shubhamNvidia Sep 17, 2026
47a2a96
fix(audio-advanced): resolve contract test lint
shubhamNvidia Sep 17, 2026
eefbf6f
fix(audio-agent): sync segmentation review fixes
shubhamNvidia Sep 17, 2026
36e0db7
fix(audio-agent): sync filtering review fixes
shubhamNvidia Sep 17, 2026
d1ee27a
fix(tagging): reject incompatible key aliases
shubhamNvidia Sep 17, 2026
ff377a1
fix(audio-inference): align fan-out iteration keys
shubhamNvidia Sep 17, 2026
88c9763
fix(audio): preserve ALM compatibility contracts
shubhamNvidia Sep 17, 2026
c908e06
fix(audio-alm): preserve falsey reconciliation ids
shubhamNvidia Sep 17, 2026
42a9d7a
fix(audio-postprocessing): sync rereview fixes
shubhamNvidia Sep 17, 2026
4e615c1
fix(audio-datasets): validate readspeech key remapping
shubhamNvidia Sep 18, 2026
0822531
fix(audio-postprocessing): preserve extraction edge cases
shubhamNvidia Sep 18, 2026
7a3a4c1
fix(audio-io): make segment extraction restart-safe
shubhamNvidia Sep 18, 2026
40265c0
merge: sync current upstream main
shubhamNvidia Sep 18, 2026
eaad369
test(audio-agent): sync integrated compatibility expectations
shubhamNvidia Sep 18, 2026
21c9348
fix(audio-io): cover extraction compatibility edges
shubhamNvidia Sep 18, 2026
79b2324
fix(audio): resolve cross-PR integration blockers
shubhamNvidia Sep 18, 2026
0db5c7b
fix(audio-filtering): preserve resident audio semantics
shubhamNvidia Sep 18, 2026
dfaad7e
fix(audio-agent): harden secrets and temporary outputs
shubhamNvidia Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills/audio-curation/SKILL.md
1 change: 1 addition & 0 deletions .agents/skills/audio-curation/references
1 change: 1 addition & 0 deletions .agents/skills/audio-stage-authoring/SKILL.md
1 change: 1 addition & 0 deletions .agents/skills/checkpoint-placement/SKILL.md
1 change: 1 addition & 0 deletions .claude/skills/audio-curation/SKILL.md
1 change: 1 addition & 0 deletions .claude/skills/audio-curation/references
13 changes: 11 additions & 2 deletions .claude/skills/getting-started/scripts/verify_audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
"""Verify audio modality dependencies are installed."""

import nemo.collections.asr as nemo_asr
from nemo_curator.stages.audio.inference.asr_nemo import InferenceAsrNemoStage

print("✓ Audio modality imports verified")
from nemo_curator.models.asr.nemo_asr import NeMoASRAdapter
from nemo_curator.stages.audio.inference.asr.stage import ASRStage

adapter = NeMoASRAdapter(model_id="nvidia/stt_en_fastconformer_ctc_large")
stage = ASRStage(
adapter_target="nemo_curator.models.asr.nemo_asr.NeMoASRAdapter",
model_id=adapter.model_id,
audio_filepath_key="audio_filepath",
)

print(f"✓ Audio modality imports verified ({nemo_asr.__name__}, {type(stage).__name__}, {type(adapter).__name__})")
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ alm_output/
benchmark_results/

CLAUDE.md
# ...but the audio agent's own instructions are part of the tool surface and must ship:
# each AGENTS.md auto-attaches for work in its directory, and each CLAUDE.md is the
# one-line `@AGENTS.md` import that gives Claude Code the same text.
!nemo_curator/audio_agent/AGENTS.md
!nemo_curator/audio_agent/CLAUDE.md
!nemo_curator/stages/audio/AGENTS.md
!nemo_curator/stages/audio/CLAUDE.md
.claude/settings.local.json

# Fern: generated API reference from `libraries` in docs.yml (`fern docs md generate`).
Expand All @@ -167,3 +174,8 @@ fern/product-docs/

# PDF parsing data (symlinked to external storage)
pdf_parsing/

# Audio agent run/artifact store: run records plus a rebuildable SQLite index, written to
# <cwd>/.audio_agent_runs unless AUDIO_AGENT_WORKSPACE points elsewhere. Local execution
# state, not source -- running the agent from the repo root must not dirty the tree.
.audio_agent_runs/
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
NeMo Curator is a scalable library for preparing multimodal datasets. Pipelines
are composed of `ProcessingStage` objects executed by a backend (Ray Data, Xenna, Ray Actor Pool) over streams of `Task` objects.

## Audio curation tasks

For any task involving audio files or audio datasets — quality filtering, VAD,
transcription, WER filtering, diarization, ALM windowing, resampling, channel
conversion, manifest creation, or inspecting an audio corpus — route the work
through the `audio-curation` skill **before doing anything else**:

- Invoke the `audio-curation` skill as your first action.
- Follow the skill's workflow end-to-end (context → route → validate → smoke →
confirm → run → report).
- Do **not** write ad-hoc scripts (ffprobe, librosa, soundfile, torchaudio, etc.)
to inspect or process audio, even for a "quick" one-off.
- Do **not** edit any Curator stage or pipeline source to force a particular
dataset to produce output. Empty output is a data/config problem, not a code bug.

The full procedure and guardrails live in
[`nemo_curator/audio_agent/skills/audio-curation/SKILL.md`](nemo_curator/audio_agent/skills/audio-curation/SKILL.md).

## Core abstractions

| Abstraction | Location | Role |
Expand Down
250 changes: 250 additions & 0 deletions nemo_curator/audio_agent/AGENTS.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions nemo_curator/audio_agent/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
138 changes: 138 additions & 0 deletions nemo_curator/audio_agent/ENVIRONMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Environment guide

One place to understand the environment the audio agent needs, check whether *your* machine is
healthy, and fix what isn't. The `doctor` verb is the runnable version of this document — it
probes the machine and prints per-issue fix steps.

## Check your machine

```bash
python -m nemo_curator.audio_agent doctor # human-readable health report + fixes
python -m nemo_curator.audio_agent doctor --json # same report as JSON (for tooling/agents)
```

Run this **first** whenever something env-related looks wrong, or **before a heavy GPU run**.
It is the single source of truth for environment health — capability cards and the failure
taxonomy point here instead of restating setup fixes.

`doctor` is machine-wide. Once a recipe exists, `validate`, `smoke`, and `run`
also return `environment_decision`, which filters those facts to the selected
flattened execution stages. A relevant blocker refuses agent-driven execution
before Ray/model setup and returns grounded choices; an irrelevant CUDA warning
does not block a CPU-only recipe. No choice is applied automatically.

To analyze a captured import/CUDA/Ray/model/runtime failure:

```bash
python -m nemo_curator.audio_agent diagnose --error '...' --recipe recipe.yaml
```

The result contains sanitized evidence, a failure classification, fresh
environment facts, applicable options, and a user-decision prompt. Unknown
failures stay unknown and receive diagnostic steps rather than a guessed fix.
Common disk-full, permission/mount, native-library/ABI, CUDA initialization, TLS,
dependency, and Ray-worker failures have distinct classifications; new signatures
remain additive in the versioned failure taxonomy.

Machine facts are scoped to where execution will happen. For an external Ray
cluster or caller-supplied executor, local driver GPU, ffmpeg, credential, Python,
disk, and worker-launch facts are not claimed as remote facts. The packet marks
the target environment unverified and asks for a bounded target-side smoke.
Unknown external GPU VRAM may be tested by that bounded smoke, but a full run
still refuses until target capacity (or equivalent target-bound evidence) is
available. A caller-supplied custom executor owns its scheduling; the agent
never substitutes the driver's CPUs/GPUs as that executor's capacity.

Overall status is the worst of the individual checks:

- **ok** — healthy.
- **warn** — a limitation or a missing optional (no GPU → CPU-only, unsupported interpreter,
missing extra, low disk). Light pipelines still run.
- **fail** — broken/misconfigured; a common GPU workload *will* fail here (e.g. a GPU-driver vs
CUDA-toolkit mismatch). Fix the FAILs before GPU model runs.

## What it checks (and how to fix)

### `python` — interpreter vs the project's `requires-python`
Confirms the interpreter is in the supported range. If not, recreate the venv with a supported
interpreter. Note: an *unsupported* interpreter is **not** the same as "CUDA is broken" — those
are separate checks, so a healthy Python here rules it out as the cause of GPU failures.

### `gpu` — GPU present + VRAM
`ok` when a CUDA GPU is visible. When it is not, the report distinguishes a
CPU-only torch build, `CUDA_VISIBLE_DEVICES` masking, visible NVIDIA devices with
failed torch initialization, driver/device-exposure failures, and genuinely
undetected hardware. These are not interchangeable: the grounded choices may be
to repair the host driver, expose/request a GPU allocation, restore the GPU
project environment, use another GPU host, or propose a CPU recipe. CPU is shown
as a conditional candidate only when every selected execution leaf explicitly
supports it; it is not called executable until the new recipe builds, plans,
validates, and passes a bounded smoke.

### `cuda_driver_toolkit` — GPU driver vs the CUDA toolkit torch was built with
The most important GPU check. `torch` bundles a CUDA **runtime** (`torch.version.cuda`, e.g.
`12.9`); the **driver** supports up to some max CUDA (`nvidia-smi`, e.g. `12.6`). Basic ops run
under minor-version compatibility, but anything that **JIT-compiles PTX at runtime** — NVRTC /
CUDA-graph decoders like NeMo's RNNT/TDT ASR — targets the toolkit's PTX ISA, which an **older
driver cannot load** → `CUDA_ERROR_UNSUPPORTED_PTX_VERSION` (error **222**).

Fix (any one):

- **Upgrade the NVIDIA driver** to one that supports the CUDA version torch was built for.
- **Install a torch built for the driver's CUDA** (a matching `+cuXXX` wheel, e.g. `+cu126`).
- **Sidestep the JIT path** for ASR *alignment*: set `decoder_type='ctc'` on
`NeMoASRAlignerStage` / `SplitASRAlignJoinStage` (the hybrid `tdt_ctc` checkpoint has a CTC
head, so no CUDA graphs and no model change). Note: plain `InferenceAsrNemoStage` with a
pure-TDT checkpoint has no CTC head — there the env fix (or a CTC-capable model) is the only
option.

The recipe-aware packet filters these options: CTC is never offered for an
unrelated metric such as UTMOS or for pure-TDT transcription, and a CPU variant
is unavailable when even one selected leaf is GPU-only.
The known mismatch is a hard preflight blocker only for a selected path known
to use runtime PTX/JIT/CUDA graphs (for example RNNT/TDT decode). Other GPU
stages receive a warning and bounded-smoke recommendation because precompiled
kernels may still work; the agent does not stop an existing working pipeline
without stage-specific evidence.

### `ffmpeg` — audio I/O
Needed for resample/convert and compressed formats (mp3/opus/…). Install with
`apt-get install ffmpeg`, `conda install -c conda-forge ffmpeg`, or `brew install ffmpeg`.

### `audio_extras` — importable audio dependencies
Install an audio dependency profile: `audio_cuda12` (GPU) or `audio_cpu` (CPU). In a
source checkout that is `uv sync --extra <profile>`; for an installed package the
command differs (and carries release-specific details), so take the current one from
the project's audio setup guide rather than from this file:
<https://docs.nvidia.com/nemo/curator/get-started/audio>.
`doctor` already picks the form that matches how this package is installed.
The fast probe checks package discoverability; a later native-library/ABI import
failure is classified from its actual error and analyzed with `diagnose`.

### `worker_env` — will a Ray **worker** import what the driver can?
Every other check probes *this* process, but pipelines execute in Ray **workers**. Ray's `uv`
integration notices the driver was started by `uv run` and rebuilds the worker environment by
re-running that command line — and `uv run` **without** an extra resolves only the *base*
dependency set. The result is a driver that imports `soundfile`/`nemo` happily next to workers
that die on `ModuleNotFoundError`, surfacing as:

```
Node setup failed for stage Stage 02 - GetAudioDurationStage on node ...
ModuleNotFoundError: No module named 'soundfile'
```

That reads like a broken install, but the install is fine — it is a **launch-flag** problem.
Fix (either one):

- Launch the interpreter directly: `.venv/bin/python -m nemo_curator.audio_agent …`
- Or carry the extra through: `uv run --extra audio_cuda12 python -m nemo_curator.audio_agent …`

### `disk` — free space
Model downloads (hundreds of MB to several GB) and intermediate WAVs need room; point caches at
a larger volume if low.

## Adding a new environment check

`env_health.py` is a small registry: write a function that reads the probed `EnvProfile` and
returns a `HealthCheck(id, status, finding, impact, fix=[...])`, decorate it with `@_check`, and
it appears in `doctor` automatically. Keep generic env concerns here — not in per-stage cards.
Loading
Loading