From da196ec13145441ece313eb040c870d6225491a3 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 01:50:35 +0000 Subject: [PATCH] Add Typer range validation to numeric CLI options Let Typer/Click validate documented numeric ranges pre-flight instead of deferring to the API, matching how the CLI already delegates enum/choice validation to Typer: - transcribe: --content-safety-confidence (25-100), --speech-threshold (0-1), --speakers-expected (>=1) - stream: --end-of-turn-confidence-threshold (0-1), --vad-threshold (0-1), --voice-focus-threshold (0-1), --max-speakers (>=1) Regenerated the affected --help snapshots. https://claude.ai/code/session_012AxuuPVkJJxNJtmZamUUna --- aai_cli/commands/stream.py | 16 ++++- aai_cli/commands/transcribe.py | 5 ++ .../test_cli_output_snapshots.ambr | 71 ++++++++++--------- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/aai_cli/commands/stream.py b/aai_cli/commands/stream.py index ca739c6b..5836434b 100644 --- a/aai_cli/commands/stream.py +++ b/aai_cli/commands/stream.py @@ -157,6 +157,8 @@ def stream( None, "--end-of-turn-confidence-threshold", help="End-of-turn confidence (0-1).", + min=0.0, + max=1.0, rich_help_panel=help_panels.OPT_TURNS, ), min_turn_silence: int | None = typer.Option( @@ -174,7 +176,9 @@ def stream( vad_threshold: float | None = typer.Option( None, "--vad-threshold", - help="Voice-activity threshold.", + help="Voice-activity threshold (0-1).", + min=0.0, + max=1.0, rich_help_panel=help_panels.OPT_TURNS, ), format_turns: bool | None = typer.Option( @@ -194,7 +198,11 @@ def stream( None, "--speaker-labels", help="Label speakers.", rich_help_panel=help_panels.OPT_SPEAKERS ), max_speakers: int | None = typer.Option( - None, "--max-speakers", help="Max speakers.", rich_help_panel=help_panels.OPT_SPEAKERS + None, + "--max-speakers", + help="Max speakers.", + min=1, + rich_help_panel=help_panels.OPT_SPEAKERS, ), # features voice_focus: NoiseSuppressionModel | None = typer.Option( @@ -206,7 +214,9 @@ def stream( voice_focus_threshold: float | None = typer.Option( None, "--voice-focus-threshold", - help="Voice-focus threshold.", + help="Voice-focus threshold (0-1).", + min=0.0, + max=1.0, rich_help_panel=help_panels.OPT_FEATURES, ), inactivity_timeout: int | None = typer.Option( diff --git a/aai_cli/commands/transcribe.py b/aai_cli/commands/transcribe.py index b4975ec3..20c99d73 100644 --- a/aai_cli/commands/transcribe.py +++ b/aai_cli/commands/transcribe.py @@ -148,6 +148,7 @@ def transcribe( None, "--speakers-expected", help="Hint speaker count.", + min=1, rich_help_panel=help_panels.OPT_SPEAKERS, ), multichannel: bool | None = typer.Option( @@ -197,12 +198,16 @@ def transcribe( None, "--content-safety-confidence", help="Content-safety confidence threshold (25-100).", + min=25, + max=100, rich_help_panel=help_panels.OPT_GUARDRAILS, ), speech_threshold: float | None = typer.Option( None, "--speech-threshold", help="Minimum proportion of speech required (0-1).", + min=0.0, + max=1.0, rich_help_panel=help_panels.OPT_GUARDRAILS, ), # analysis diff --git a/tests/__snapshots__/test_cli_output_snapshots.ambr b/tests/__snapshots__/test_cli_output_snapshots.ambr index f6b17ab0..e867dca5 100644 --- a/tests/__snapshots__/test_cli_output_snapshots.ambr +++ b/tests/__snapshots__/test_cli_output_snapshots.ambr @@ -567,26 +567,29 @@ │ (repeatable). │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Turn Detection ─────────────────────────────────────────────────────────────╮ - │ --end-of-turn-confid… FLOAT End-of-turn │ - │ confidence (0-1). │ - │ --min-turn-silence INTEGER Min silence to end a │ - │ turn (ms). │ - │ --max-turn-silence INTEGER Max silence before │ - │ ending a turn (ms). │ - │ --vad-threshold FLOAT Voice-activity │ - │ threshold. │ - │ --format-turns --no-format-turns Punctuate/format │ - │ finalized turns. │ - │ --include-partial-tu… Emit partial turns. │ + │ --end-of-turn-co… FLOAT RANGE End-of-turn │ + │ [0.0<=x<=1.0] confidence (0-1). │ + │ --min-turn-silen… INTEGER Min silence to │ + │ end a turn (ms). │ + │ --max-turn-silen… INTEGER Max silence │ + │ before ending a │ + │ turn (ms). │ + │ --vad-threshold FLOAT RANGE Voice-activity │ + │ [0.0<=x<=1.0] threshold (0-1). │ + │ --format-turns --no-format-tur… Punctuate/format │ + │ finalized turns. │ + │ --include-partia… Emit partial │ + │ turns. │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Speakers & Channels ────────────────────────────────────────────────────────╮ - │ --speaker-labels Label speakers. │ - │ --max-speakers INTEGER Max speakers. │ + │ --speaker-labels Label speakers. │ + │ --max-speakers INTEGER RANGE [x>=1] Max speakers. │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Features ───────────────────────────────────────────────────────────────────╮ │ --voice-focus [near-field|far-field] Voice focus (noise │ │ suppression model). │ - │ --voice-focus-thresho… FLOAT Voice-focus threshold. │ + │ --voice-focus-thresho… FLOAT RANGE Voice-focus threshold │ + │ [0.0<=x<=1.0] (0-1). │ │ --inactivity-timeout INTEGER Auto-close after N │ │ seconds idle. │ ╰──────────────────────────────────────────────────────────────────────────────╯ @@ -681,28 +684,28 @@ │ --disfluencies Keep filler words (e.g. um, uh). │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Speakers & Channels ────────────────────────────────────────────────────────╮ - │ --speaker-labels Enable diarization. │ - │ --speakers-expected INTEGER Hint speaker count. │ - │ --multichannel Transcribe each audio channel │ - │ separately. │ + │ --speaker-labels Enable diarization. │ + │ --speakers-expected INTEGER RANGE [x>=1] Hint speaker count. │ + │ --multichannel Transcribe each audio │ + │ channel separately. │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Guardrails ─────────────────────────────────────────────────────────────────╮ - │ --redact-pii Redact PII from the │ - │ transcript. │ - │ --redact-pii-policy TEXT Comma-separated PII │ - │ policies (e.g. │ - │ person_name,...). │ - │ --redact-pii-sub [hash|entity_name] How to replace redacted │ - │ PII. │ - │ --redact-pii-audio Also redact audio. │ - │ --filter-profanity Mask profanity. │ - │ --content-safety Detect sensitive │ - │ content. │ - │ --content-safety-confid… INTEGER Content-safety │ - │ confidence threshold │ - │ (25-100). │ - │ --speech-threshold FLOAT Minimum proportion of │ - │ speech required (0-1). │ + │ --redact-pii Redact PII from the │ + │ transcript. │ + │ --redact-pii-policy TEXT Comma-separated PII │ + │ policies (e.g. │ + │ person_name,...). │ + │ --redact-pii-sub [hash|entity_name] How to replace │ + │ redacted PII. │ + │ --redact-pii-audio Also redact audio. │ + │ --filter-profanity Mask profanity. │ + │ --content-safety Detect sensitive │ + │ content. │ + │ --content-safety-conf… INTEGER RANGE Content-safety │ + │ [25<=x<=100] confidence threshold │ + │ (25-100). │ + │ --speech-threshold FLOAT RANGE Minimum proportion of │ + │ [0.0<=x<=1.0] speech required (0-1). │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Analysis ───────────────────────────────────────────────────────────────────╮ │ --summarization Summarize the │