Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5e760a5
feat(audio): agent-ready foundation — contract layer, residency, disc…
shubhamNvidia Aug 25, 2026
1833624
fix(audio): address safe agent foundation review findings
shubhamNvidia Sep 4, 2026
fbf865b
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 4, 2026
813b6bf
fix(audio): three silent-wrong-data findings from the foundation review
shubhamNvidia Sep 4, 2026
195f0c6
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 7, 2026
948166d
fix(audio): three more validate-clean-then-fail findings
shubhamNvidia Sep 8, 2026
d446f25
fix(audio): harden foundation validation edge cases
shubhamNvidia Sep 9, 2026
26a2da8
fix(audio): avoid folder item ID collisions
shubhamNvidia Sep 9, 2026
3158004
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 10, 2026
89dde01
fix(audio): support scoped tagging contracts
shubhamNvidia Sep 10, 2026
454ff92
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 15, 2026
54f655e
fix(audio-agent): validate hidden and residency parameters
shubhamNvidia Sep 15, 2026
9db13eb
fix(audio-agent): support conditional and nested contracts
shubhamNvidia Sep 15, 2026
42c94a0
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 15, 2026
9a47a9a
fix(audio-agent): require literal keys for generic reads
shubhamNvidia Sep 15, 2026
bf69fbb
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 16, 2026
fcaa6ca
fix(audio-agent): preserve filtering residency consistency
shubhamNvidia Sep 16, 2026
04a9ada
fix(audio-agent): scope residency, literals, and positional compatibi…
shubhamNvidia Sep 16, 2026
e3d457e
fix(audio-agent): support optional contract reads
shubhamNvidia Sep 16, 2026
b26e5d3
fix(audio): preserve resident waveform samples
shubhamNvidia Sep 16, 2026
38aeea0
fix(audio-agent): sync shared contract support
shubhamNvidia Sep 16, 2026
3a2ba2f
fix(audio): plan conditional writes honestly; restart-safe ManifestWr…
shubhamNvidia Sep 17, 2026
e0e0839
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 17, 2026
0367061
fix(audio-agent): model invalidated provenance keys
shubhamNvidia Sep 17, 2026
5847683
fix(audio-agent): validate conditional read branches
shubhamNvidia Sep 17, 2026
b261c5d
fix(audio-agent): prevent unsafe bounded-source delta reuse
shubhamNvidia Sep 18, 2026
be9118e
fix(audio): close agent foundation review gaps
shubhamNvidia Sep 18, 2026
ccc23ed
fix(audio): validate resident sample rates
shubhamNvidia Sep 18, 2026
e789524
fix(audio): harden foundation residency completion
shubhamNvidia Sep 18, 2026
0dad5b9
fix(audio): close foundation review gaps
shubhamNvidia Sep 18, 2026
df1d8fd
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 19, 2026
0e9634a
fix(audio): normalize PCM and validate sample rates
shubhamNvidia Sep 19, 2026
b041038
fix(audio): preserve normalized waveform identity
shubhamNvidia Sep 21, 2026
c793f9f
Merge branch 'main' into agent/foundation
shubhamNvidia Sep 21, 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
3 changes: 3 additions & 0 deletions nemo_curator/pipeline/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ def run( # noqa: C901, PLR0912
else:
result = self._run_with_resumability(executor, initial_tasks, checkpoint_path)

for stage in self.stages:
stage.finalize()
Comment on lines +342 to +343

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Finalizer failure blocks cleanup

If any stage's finalize() call raises, this loop stops immediately. Later stages then cannot publish their successful lifecycle state, and the Slurm shard completion manifest is skipped. For example, an ownership or file-identity error from one checkpoint can leave a later valid checkpoint without its _COMPLETE marker. Each stage finalizer should be attempted before finalization errors are propagated.

Knowledge Base Used:


if completion_manifest is not None:
if failed_task_manifest_exists():
logger.warning(
Expand Down
57 changes: 57 additions & 0 deletions nemo_curator/stages/audio/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Audio stages — agent guardrails

These instructions apply to any AI coding agent working in `nemo_curator/stages/audio/`.
Codex and Cursor load this nested `AGENTS.md` automatically; Claude Code reaches it
through the sibling `CLAUDE.md` import.

Two different jobs happen in this directory, and they have opposite rules about editing.

## If you are curating a dataset, this directory is read-only

Stage source is shared library code. Never change a stage, a threshold, a filter or
windowing logic to make one user's dataset produce the output they hoped for — diagnose
from the data instead. Inspect stage contracts through the public
`nemo_curator.stages.audio.agent` facade rather than reading stage source to answer what
a stage reads or writes: `agent.describe_stage("MyStage")` is the sanctioned answer, and
`agent.find_producers("role")` says which stages can produce a semantic role.

## If you are authoring or fixing a stage, start here

Read `AGENT_READY.md` in this directory. It is the authoritative checklist and it is
maintained with the framework; work from it rather than from memory.

**Golden rule: every new knob defaults to today's behavior.** Agent-readiness is a
declaration layer over working code. If a change alters what an existing pipeline
produces, it is a behavior change and needs its own justification, not a checklist entry.

The mechanical contract is three things, each detailed in `AGENT_READY.md`:

1. Inherit `AgentReady` and implement `describe()` returning a `StageContract` with
`reads`, `writes`, `cardinality` and honest `gates`.
2. Make every `task.data` key you read or write a `*_key` constructor field — no bare key
literals in `process()`, or the key is invisible to the agent and cannot be remapped.
3. Add `assert_agent_ready(MyStage(...), fixture_factory=...)` as a test.

Document what each externally consumed output means in the stage docstring and tests.
Roles prove that two stages can connect; clear semantic documentation lets reviewers
judge whether connecting them serves the user's intent.

Follow the repo's existing stage conventions while you do it:
`.cursor/rules/processing-stage-patterns.mdc` and
`.cursor/rules/composite-stage-patterns.mdc`. Those are upstream-maintained framework
rules — read them, never edit them.

Declare honestly even where it costs you: a stage that may drop rows is
`cardinality="filter"` even when dropping is incidental, and `gates` are environment facts
rather than aspirations. An optimistic contract is worse than a missing one, because the
planner treats it as ground truth.

## Verify before you claim done

```bash
.venv/bin/python -m pytest tests/stages/audio -m "not gpu" -q
.venv/bin/python -c 'from nemo_curator.stages.audio import agent; print(agent.describe_stage("MyStage").to_dict())'
```

If `describe` does not match what the code actually touches for those params, the contract
is wrong no matter what the tests say.
346 changes: 346 additions & 0 deletions nemo_curator/stages/audio/AGENT_READY.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions nemo_curator/stages/audio/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
10 changes: 10 additions & 0 deletions nemo_curator/stages/audio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,17 @@
"AbbreviationConcatStage": "nemo_curator.stages.audio.text_filtering",
"AudioDataFilterStage": "nemo_curator.stages.audio.advanced_pipelines",
"BandFilterStage": "nemo_curator.stages.audio.filtering",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nemo_curator/stages/audio/__init__.py:30-74 adds other stages from this PR to
both _LAZY and __all__, but omits
CreateInitialManifestAudioFolderStage. Although the PR presents it as the
user-facing way to start a pipeline from a folder, the conventional import
from nemo_curator.stages.audio import CreateInitialManifestAudioFolderStage
raises ImportError and hasattr(nemo_curator.stages.audio, ...) is false.

Add the class to both public-name tables and cover the top-level import.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, oversight. Added to both _LAZY and all, with the top-level import covered.

"ChannelCountStage": "nemo_curator.stages.audio.preprocessing",
"CreateInitialManifestAudioFolderStage": "nemo_curator.stages.audio.common",
"GetAudioDurationStage": "nemo_curator.stages.audio.common",
"ManifestCheckpointStage": "nemo_curator.stages.audio.common",
"ManifestReader": "nemo_curator.stages.audio.common",
"ManifestWriterStage": "nemo_curator.stages.audio.common",
"MonoConversionStage": "nemo_curator.stages.audio.preprocessing",
"PreserveByValueConditionsStage": "nemo_curator.stages.audio.common",
"PreserveByValueStage": "nemo_curator.stages.audio.common",
"RegexSubstitutionStage": "nemo_curator.stages.audio.text_filtering",
"SampleRateFilterStage": "nemo_curator.stages.audio.preprocessing",
"SIGMOSFilterStage": "nemo_curator.stages.audio.filtering",
"SegmentConcatenationStage": "nemo_curator.stages.audio.preprocessing",
"SpeakerSeparationStage": "nemo_curator.stages.audio.segmentation",
Expand All @@ -54,13 +59,18 @@
"AbbreviationConcatStage",
"AudioDataFilterStage",
"BandFilterStage",
"ChannelCountStage",
"CreateInitialManifestAudioFolderStage",
"GetAudioDurationStage",
"ManifestCheckpointStage",
"ManifestReader",
"ManifestWriterStage",
"MonoConversionStage",
"PreserveByValueConditionsStage",
"PreserveByValueStage",
"RegexSubstitutionStage",
"SIGMOSFilterStage",
"SampleRateFilterStage",
"SegmentConcatenationStage",
"SpeakerSeparationStage",
"TimestampMapperStage",
Expand Down
29 changes: 29 additions & 0 deletions nemo_curator/stages/audio/_agent/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Private foundation for agent-driven audio pipeline construction.

These modules are the STAGE-SIDE declaration layer: the vocabulary a stage uses
to describe itself (``StageContract``, ``Gates``, ``IOSpec``, the ``AgentReady``
mixin, the shared role names) plus the discovery, planning and conformance code
that reads it. They live under ``stages/audio`` -- not under ``nemo_curator.audio_agent``
-- on purpose: 43 stage modules import ``_agent_ready`` and 16 call into
``_residency`` from inside ``process()``. Moving them into the agent package would
make ``nemo_curator.stages.audio`` unusable without the agent installed, inverting
a dependency that today points one way only.

Grouped into this subpackage purely so the stage tree reads as stages. Import the
public facade -- :mod:`nemo_curator.stages.audio.agent` -- rather than these
modules directly.
"""
Loading
Loading