From a193a1a4a67874f4f082c2077cdab77cc9692401 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 12:59:25 +0000 Subject: [PATCH] Rename agent-framework command and template to agent-cascade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "framework" label was misleading: the command runs a single live conversation in the terminal (it ships no framework), and the thing that distinguishes it from `assembly agent` is that you orchestrate the cascade yourself — Streaming STT → LLM Gateway → streaming TTS — instead of calling the managed Voice Agent endpoint. "cascade" is the word the codebase already uses to explain the feature, so `agent-cascade` reads accurately and pairs naturally with `agent` in the help panel. Renames in lockstep: the `agent-cascade` CLI command, the `assembly init agent-cascade` template, the internal `aai_cli/agent_cascade` and `aai_cli/commands/agent_cascade` packages, tests, docs, and the regenerated help snapshots. https://claude.ai/code/session_01WYJoTJ5Pw9kwsfMZmN19Fe --- .importlinter | 2 +- README.md | 2 +- REFERENCE.md | 2 +- aai_cli/AGENTS.md | 2 +- .../__init__.py | 6 +- .../config.py | 4 +- .../engine.py | 8 +- .../text.py | 0 .../voices.py | 2 +- aai_cli/app/agent_shared.py | 2 +- aai_cli/app/init_exec.py | 2 +- .../__init__.py | 32 ++++---- .../_exec.py | 22 ++--- aai_cli/init/templates/__init__.py | 6 +- .../AGENTS.md | 0 .../Dockerfile | 0 .../Procfile | 0 .../README.md | 4 +- .../__init__.py | 0 .../api/__init__.py | 0 .../api/cascade.py | 4 +- .../api/index.py | 4 +- .../api/settings.py | 0 .../dockerignore | 0 .../env.example | 2 +- .../gitignore | 0 .../requirements.txt | 0 .../runtime.txt | 0 .../static/app.js | 0 .../static/audio.js | 0 .../static/index.html | 0 .../static/styles.css | 0 .../vercel.json | 0 .../test_snapshots_help_build.ambr | 2 +- .../test_snapshots_help_root.ambr | 82 +++++++++---------- .../test_snapshots_help_run.ambr | 18 ++-- ...{_agent_framework.py => _agent_cascade.py} | 4 +- ...mmand.py => test_agent_cascade_command.py} | 38 ++++----- ...config.py => test_agent_cascade_config.py} | 4 +- ...engine.py => test_agent_cascade_engine.py} | 8 +- ...ork_text.py => test_agent_cascade_text.py} | 2 +- ...voices.py => test_agent_cascade_voices.py} | 2 +- tests/test_init_command.py | 2 +- tests/test_init_scaffold.py | 2 +- ...py => test_init_template_agent_cascade.py} | 6 +- ...> test_init_template_agent_cascade_api.py} | 4 +- ...test_init_template_agent_cascade_reply.py} | 6 +- ...> test_init_template_agent_cascade_stt.py} | 4 +- tests/test_init_templates.py | 2 +- tests/test_smoke.py | 2 +- 50 files changed, 146 insertions(+), 148 deletions(-) rename aai_cli/{agent_framework => agent_cascade}/__init__.py (76%) rename aai_cli/{agent_framework => agent_cascade}/config.py (89%) rename aai_cli/{agent_framework => agent_cascade}/engine.py (97%) rename aai_cli/{agent_framework => agent_cascade}/text.py (100%) rename aai_cli/{agent_framework => agent_cascade}/voices.py (96%) rename aai_cli/commands/{agent_framework => agent_cascade}/__init__.py (80%) rename aai_cli/commands/{agent_framework => agent_cascade}/_exec.py (83%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/AGENTS.md (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/Dockerfile (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/Procfile (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/README.md (94%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/__init__.py (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/api/__init__.py (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/api/cascade.py (99%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/api/index.py (89%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/api/settings.py (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/dockerignore (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/env.example (81%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/gitignore (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/requirements.txt (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/runtime.txt (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/static/app.js (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/static/audio.js (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/static/index.html (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/static/styles.css (100%) rename aai_cli/init/templates/{agent_framework => agent_cascade}/vercel.json (100%) rename tests/{_agent_framework.py => _agent_cascade.py} (97%) rename tests/{test_agent_framework_command.py => test_agent_cascade_command.py} (87%) rename tests/{test_agent_framework_config.py => test_agent_cascade_config.py} (84%) rename tests/{test_agent_framework_engine.py => test_agent_cascade_engine.py} (98%) rename tests/{test_agent_framework_text.py => test_agent_cascade_text.py} (95%) rename tests/{test_agent_framework_voices.py => test_agent_cascade_voices.py} (96%) rename tests/{test_init_template_agent_framework.py => test_init_template_agent_cascade.py} (99%) rename tests/{test_init_template_agent_framework_api.py => test_init_template_agent_cascade_api.py} (98%) rename tests/{test_init_template_agent_framework_reply.py => test_init_template_agent_cascade_reply.py} (98%) rename tests/{test_init_template_agent_framework_stt.py => test_init_template_agent_cascade_stt.py} (96%) diff --git a/.importlinter b/.importlinter index ef910f60..0e2ffa89 100644 --- a/.importlinter +++ b/.importlinter @@ -32,7 +32,7 @@ type = forbidden ; deliberate, so this short list does not drift the way the old core list did. source_modules = aai_cli.agent - aai_cli.agent_framework + aai_cli.agent_cascade aai_cli.auth aai_cli.code_gen aai_cli.init diff --git a/README.md b/README.md index 26837579..027bf02a 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ That's it. Run `assembly onboard` for a guided tour, or see [Installation](#-ins | `assembly stream` | Real-time transcription from your microphone, a file, or a URL — on macOS it can capture system audio too | | `assembly dictate` | Push-to-talk dictation: press Enter to record, Enter again for instant text (Sync STT API, up to 120 s per utterance) | | `assembly agent` | Full-duplex spoken conversation with a voice agent, right in your terminal | -| `assembly agent-framework` | Same live conversation, but wired client-side from Streaming STT + the LLM Gateway + streaming TTS, like the `agent-framework` starter (sandbox-only) | +| `assembly agent-cascade` | Same live conversation, but wired client-side from Streaming STT + the LLM Gateway + streaming TTS, like the `agent-cascade` starter (sandbox-only) | | `assembly speak` | Synthesize text to speech over the streaming-TTS WebSocket (sandbox-only) | | `assembly llm` | Prompt the LLM Gateway over a transcript, stdin, or a live stream | | `assembly clip` | Cut audio/video with ffmpeg by diarized speaker, text match, LLM pick, or time range (`--video` keeps the picture for URL sources) — clip boundaries snap into nearby silence | diff --git a/REFERENCE.md b/REFERENCE.md index 443b63e2..0e13314c 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -76,7 +76,7 @@ each carrying a `"type"` field to dispatch on: | ------- | ----------- | | `assembly stream --json` | `begin`, `turn`, `termination` | | `assembly agent --json` | `session.ready`, `transcript.user.delta`, `transcript.user`, `reply.started`, `transcript.agent`, `reply.done` | -| `assembly agent-framework --json` | `session.ready`, `transcript.user.delta`, `transcript.user`, `reply.started`, `transcript.agent`, `reply.done` | +| `assembly agent-cascade --json` | `session.ready`, `transcript.user.delta`, `transcript.user`, `reply.started`, `transcript.agent`, `reply.done` | | `assembly dictate --json` | `utterance` | | `assembly llm --follow --json` | `answer` | | `assembly transcribe --json` | `result` (one per source) | diff --git a/aai_cli/AGENTS.md b/aai_cli/AGENTS.md index fe6444f6..50303b89 100644 --- a/aai_cli/AGENTS.md +++ b/aai_cli/AGENTS.md @@ -151,7 +151,7 @@ heavily-reworked commands with long bodies; small commands keep the inline - **`streaming/`** + `client.stream_audio` — v3 realtime API. Event callbacks run on the SDK reader thread and guard against `BrokenPipeError` (`stdio.silence_stdout()`) so a closed pipe never dumps a thread traceback. - **`core/sync_stt.py`** + **`core/hotkey.py`** + `commands/dictate/` — `assembly dictate`: push-to-talk dictation over the **Sync STT API** (`Environment.sync_base`, one POST `/transcribe` per utterance with the required `X-AAI-Model: u3-sync-pro` header; 80 ms–120 s of PCM/WAV). `hotkey.TerminalKeys` scopes stdin into cbreak (Ctrl-C still signals) and reads single keypresses; `dictate_exec._record` polls it with a zero timeout between ~100 ms mic chunks. All three boundaries (keys, mic, HTTP) are injectable, so the suite never needs a real terminal — `tests/test_hotkey.py` drives a pty pair for the termios behavior. - **`agent/`** — full-duplex voice agent (mic in, TTS out via `voices.py`). -- **`agent_framework/`** + `commands/agent_framework/` — `assembly agent-framework`: the same live terminal conversation as `assembly agent`, but **client-orchestrated** — `engine.run_cascade` wires Streaming STT → the LLM Gateway → streaming TTS itself instead of talking to the Voice Agent endpoint, mirroring what the `agent-framework` `assembly init` template does server-side. **Sandbox-only** (streaming TTS has no prod host; guarded via `tts.session.require_available`). Reuses the agent slice's `DuplexAudio`/`AgentRenderer` and `core.client.stream_audio`/`core.llm.complete`/`tts.session.synthesize`; the three network legs are injected through `engine.CascadeDeps` (the `tts/session.py` seam) so the cascade — greeting, per-sentence TTS, barge-in, history window — is unit-tested against fakes with no sockets/mic/speaker. +- **`agent_cascade/`** + `commands/agent_cascade/` — `assembly agent-cascade`: the same live terminal conversation as `assembly agent`, but **client-orchestrated** — `engine.run_cascade` wires Streaming STT → the LLM Gateway → streaming TTS itself instead of talking to the Voice Agent endpoint, mirroring what the `agent-cascade` `assembly init` template does server-side. **Sandbox-only** (streaming TTS has no prod host; guarded via `tts.session.require_available`). Reuses the agent slice's `DuplexAudio`/`AgentRenderer` and `core.client.stream_audio`/`core.llm.complete`/`tts.session.synthesize`; the three network legs are injected through `engine.CascadeDeps` (the `tts/session.py` seam) so the cascade — greeting, per-sentence TTS, barge-in, history window — is unit-tested against fakes with no sockets/mic/speaker. - **`tts/`** + `commands/speak.py` — `assembly speak` synthesizes text to speech over the sandbox streaming-TTS WebSocket (`streaming-tts.sandbox000.…`). **Sandbox-only:** `session.is_available()` is false in production (empty `Environment.streaming_tts_host`), so the command exits 2 with a `--sandbox` hint. `session.synthesize` drives a Begin→Generate→Flush→Audio→Terminate protocol with an injectable `connect` for hermetic tests (mirrors `agent/session.py`); `audio.py` plays the PCM (default) or writes a WAV (`--out`). - **`code_gen/`** — backs `--show-code` on `transcribe`/`stream`/`agent`: builds a ready-to-run Python SDK script from exactly the flags passed (no API key needed; generated code reads `ASSEMBLYAI_API_KEY`). - **`auth/`** — browser-assisted `assembly login` via AMS + **Stytch B2B OAuth discovery** (`discovery.py`, `flow.py`, `loopback.py`, `ams.py`). Not Stytch Connected Apps. diff --git a/aai_cli/agent_framework/__init__.py b/aai_cli/agent_cascade/__init__.py similarity index 76% rename from aai_cli/agent_framework/__init__.py rename to aai_cli/agent_cascade/__init__.py index a8a89173..8807ebfc 100644 --- a/aai_cli/agent_framework/__init__.py +++ b/aai_cli/agent_cascade/__init__.py @@ -1,9 +1,9 @@ -"""The terminal *agent framework* slice: a client-orchestrated voice cascade. +"""The terminal *agent cascade* slice: a client-orchestrated voice cascade. -`assembly agent-framework` holds the same kind of live voice conversation as +`assembly agent-cascade` holds the same kind of live voice conversation as `assembly agent`, but where `agent` talks to AssemblyAI's single Voice Agent endpoint, this slice wires the three primitives together itself — Streaming STT --> the LLM Gateway -> streaming TTS — exactly like the ``agent-framework`` +-> the LLM Gateway -> streaming TTS — exactly like the ``agent-cascade`` ``assembly init`` template does server-side. Because it uses streaming TTS it is sandbox-only. diff --git a/aai_cli/agent_framework/config.py b/aai_cli/agent_cascade/config.py similarity index 89% rename from aai_cli/agent_framework/config.py rename to aai_cli/agent_cascade/config.py index 4d41fc3c..ac44810b 100644 --- a/aai_cli/agent_framework/config.py +++ b/aai_cli/agent_cascade/config.py @@ -1,6 +1,6 @@ """Per-run configuration for the terminal voice cascade. -Defaults mirror the ``agent-framework`` ``assembly init`` template's +Defaults mirror the ``agent-cascade`` ``assembly init`` template's ``api/settings.py`` so the CLI conversation and the scaffolded app behave the same out of the box. """ @@ -9,7 +9,7 @@ from dataclasses import dataclass -from aai_cli.agent_framework.voices import DEFAULT_VOICE +from aai_cli.agent_cascade.voices import DEFAULT_VOICE from aai_cli.core import llm DEFAULT_MODEL = llm.DEFAULT_MODEL diff --git a/aai_cli/agent_framework/engine.py b/aai_cli/agent_cascade/engine.py similarity index 97% rename from aai_cli/agent_framework/engine.py rename to aai_cli/agent_cascade/engine.py index d43431e0..3ac070fb 100644 --- a/aai_cli/agent_framework/engine.py +++ b/aai_cli/agent_cascade/engine.py @@ -18,8 +18,8 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, Protocol -from aai_cli.agent_framework.config import CascadeConfig -from aai_cli.agent_framework.text import split_sentences, trim_history +from aai_cli.agent_cascade.config import CascadeConfig +from aai_cli.agent_cascade.text import split_sentences, trim_history from aai_cli.core import client, config_builder, llm from aai_cli.core.errors import CLIError from aai_cli.tts import session as tts_session @@ -96,7 +96,7 @@ def _spawn_thread(target: Callable[[], None]) -> _Worker: return thread -# The realtime model the cascade transcribes with (same as the agent-framework template). +# The realtime model the cascade transcribes with (same as the agent-cascade template). STT_SPEECH_MODEL = "u3-rt-pro" @@ -253,7 +253,7 @@ def _record_error(self, exc: CLIError) -> None: since the worker thread can't surface an exit code itself.""" if self.error is None: self.error = exc - output.error_console.print(f"[aai.warn]agent-framework:[/aai.warn] {exc.message}") + output.error_console.print(f"[aai.warn]agent-cascade:[/aai.warn] {exc.message}") def shutdown(self) -> None: """Stop and join any in-flight reply worker (run on every exit path).""" diff --git a/aai_cli/agent_framework/text.py b/aai_cli/agent_cascade/text.py similarity index 100% rename from aai_cli/agent_framework/text.py rename to aai_cli/agent_cascade/text.py diff --git a/aai_cli/agent_framework/voices.py b/aai_cli/agent_cascade/voices.py similarity index 96% rename from aai_cli/agent_framework/voices.py rename to aai_cli/agent_cascade/voices.py index 57bdc006..b6abb6e2 100644 --- a/aai_cli/agent_framework/voices.py +++ b/aai_cli/agent_cascade/voices.py @@ -1,4 +1,4 @@ -"""The voices `assembly agent-framework` speaks with. +"""The voices `assembly agent-cascade` speaks with. The cascade's audio comes from streaming TTS, so its voices are the TTS catalog (`aai_cli.tts.voices`) — not the Voice Agent voices `assembly agent` uses. This diff --git a/aai_cli/app/agent_shared.py b/aai_cli/app/agent_shared.py index 27699dab..188ea755 100644 --- a/aai_cli/app/agent_shared.py +++ b/aai_cli/app/agent_shared.py @@ -1,4 +1,4 @@ -"""Run-logic shared by the two voice commands (`agent` and `agent-framework`). +"""Run-logic shared by the two voice commands (`agent` and `agent-cascade`). Both build a live terminal conversation and resolve the persona the same way, so the shared piece lives in the `app/` layer (the `doctor_checks`/`setup_exec` diff --git a/aai_cli/app/init_exec.py b/aai_cli/app/init_exec.py index 10bfd731..5397466d 100644 --- a/aai_cli/app/init_exec.py +++ b/aai_cli/app/init_exec.py @@ -105,7 +105,7 @@ def _active_env_vars() -> dict[str, str]: "ASSEMBLYAI_STREAMING_HOST": env.streaming_host, # Voice Agent host mirrors the streaming host's naming across environments. "ASSEMBLYAI_AGENTS_HOST": env.streaming_host.replace("streaming", "agents", 1), - # Streaming-TTS host for the cascade (agent-framework) template. Empty in + # Streaming-TTS host for the cascade (agent-cascade) template. Empty in # production, where streaming TTS has no host; that template then refuses to # run and points at --sandbox. "ASSEMBLYAI_TTS_HOST": env.streaming_tts_host, diff --git a/aai_cli/commands/agent_framework/__init__.py b/aai_cli/commands/agent_cascade/__init__.py similarity index 80% rename from aai_cli/commands/agent_framework/__init__.py rename to aai_cli/commands/agent_cascade/__init__.py index 6b8c8e61..322b7de4 100644 --- a/aai_cli/commands/agent_framework/__init__.py +++ b/aai_cli/commands/agent_cascade/__init__.py @@ -5,15 +5,15 @@ import typer from aai_cli import command_registry, help_panels, options -from aai_cli.agent_framework import voices -from aai_cli.agent_framework.config import ( +from aai_cli.agent_cascade import voices +from aai_cli.agent_cascade.config import ( DEFAULT_GREETING, DEFAULT_MODEL, DEFAULT_SYSTEM_PROMPT, ) -from aai_cli.agent_framework.voices import DEFAULT_VOICE +from aai_cli.agent_cascade.voices import DEFAULT_VOICE from aai_cli.app.context import AppState, run_command, run_with_options -from aai_cli.commands.agent_framework import _exec as agent_framework_exec +from aai_cli.commands.agent_cascade import _exec as agent_cascade_exec from aai_cli.core import choices, llm from aai_cli.ui import output from aai_cli.ui.help_text import examples_epilog @@ -23,7 +23,7 @@ SPEC = command_registry.CommandModuleSpec( panel=help_panels.TRANSCRIPTION, order=45, # pragma: no mutate -- sparse rank; a +-1 shift is order-equivalent - commands=("agent-framework",), + commands=("agent-cascade",), ) @@ -35,24 +35,24 @@ def _emit_voice_list(_state: AppState, json_mode: bool) -> None: @app.command( - name="agent-framework", + name="agent-cascade", rich_help_panel=help_panels.TRANSCRIPTION, epilog=examples_epilog( [ - ("Start a live cascade conversation", "assembly --sandbox agent-framework"), + ("Start a live cascade conversation", "assembly --sandbox agent-cascade"), ( "Pick a voice and opening line", - 'assembly --sandbox agent-framework --voice michael --greeting "Hi there"', + 'assembly --sandbox agent-cascade --voice michael --greeting "Hi there"', ), ( "Give the agent a persona", - 'assembly --sandbox agent-framework --system-prompt "You are a terse pirate."', + 'assembly --sandbox agent-cascade --system-prompt "You are a terse pirate."', ), - ("See available voices", "assembly --sandbox agent-framework --list-voices"), + ("See available voices", "assembly --sandbox agent-cascade --list-voices"), ] ), ) -def agent_framework( +def agent_cascade( ctx: typer.Context, source: str | None = typer.Argument( None, help="Audio file path or URL to speak to the agent. Omit to use the microphone." @@ -97,9 +97,9 @@ def agent_framework( Like 'assembly agent', but instead of AssemblyAI's Voice Agent endpoint this wires the three primitives together itself — Streaming STT, the LLM Gateway, - and streaming TTS — exactly like the 'agent-framework' init template does + and streaming TTS — exactly like the 'agent-cascade' init template does server-side. Because it uses streaming TTS it only runs in the sandbox: run - it as 'assembly --sandbox agent-framework' (--sandbox goes before the + it as 'assembly --sandbox agent-cascade' (--sandbox goes before the subcommand). Use headphones: the mic stays open while the agent speaks, so on speakers it @@ -108,14 +108,14 @@ def agent_framework( agent's reply. This only runs a conversation in the terminal — it writes no code. To build - an agent-framework app, run 'assembly init agent-framework' instead. + an agent-cascade app, run 'assembly init agent-cascade' instead. """ if list_voices: run_command(ctx, _emit_voice_list, json=json_out) return - opts = agent_framework_exec.AgentFrameworkOptions( + opts = agent_cascade_exec.AgentCascadeOptions( source=source, sample=sample, voice=voice, @@ -126,4 +126,4 @@ def agent_framework( device=device, output_field=output_field, ) - run_with_options(ctx, agent_framework_exec.run_agent_framework, opts, json=json_out) + run_with_options(ctx, agent_cascade_exec.run_agent_cascade, opts, json=json_out) diff --git a/aai_cli/commands/agent_framework/_exec.py b/aai_cli/commands/agent_cascade/_exec.py similarity index 83% rename from aai_cli/commands/agent_framework/_exec.py rename to aai_cli/commands/agent_cascade/_exec.py index 5b7aefdc..03f8406e 100644 --- a/aai_cli/commands/agent_framework/_exec.py +++ b/aai_cli/commands/agent_cascade/_exec.py @@ -1,7 +1,7 @@ -"""Run logic for `assembly agent-framework`: the options/run split (see AGENTS.md). +"""Run logic for `assembly agent-cascade`: the options/run split (see AGENTS.md). -The command module parses argv into an ``AgentFrameworkOptions`` and hands it to -``run_agent_framework``, so tests drive validation and the cascade wiring by +The command module parses argv into an ``AgentCascadeOptions`` and hands it to +``run_agent_cascade``, so tests drive validation and the cascade wiring by constructing options directly rather than round-tripping through ``CliRunner``. """ @@ -16,8 +16,8 @@ from aai_cli.agent.audio import SAMPLE_RATE, DuplexAudio, NullPlayer from aai_cli.agent.render import AgentRenderer -from aai_cli.agent_framework import engine, voices -from aai_cli.agent_framework.config import CascadeConfig +from aai_cli.agent_cascade import engine, voices +from aai_cli.agent_cascade.config import CascadeConfig from aai_cli.app.agent_shared import resolve_system_prompt as _resolve_system_prompt from aai_cli.app.context import AppState from aai_cli.core import choices, client @@ -28,8 +28,8 @@ @dataclass(frozen=True) -class AgentFrameworkOptions: - """Every `assembly agent-framework` conversation flag as plain data. +class AgentCascadeOptions: + """Every `assembly agent-cascade` conversation flag as plain data. ``--list-voices`` is excluded: it dispatches to its own auth-free body in the command module. ``--json`` is excluded: run_command resolves it into the @@ -70,16 +70,16 @@ def _open_audio( return duplex.mic, duplex.player, SAMPLE_RATE -def run_agent_framework(opts: AgentFrameworkOptions, state: AppState, *, json_mode: bool) -> None: - """Execute one `assembly agent-framework` cascade from already-parsed flags.""" +def run_agent_cascade(opts: AgentCascadeOptions, state: AppState, *, json_mode: bool) -> None: + """Execute one `assembly agent-cascade` cascade from already-parsed flags.""" text_mode, json_mode = resolve_output_modes(opts.output_field, json_mode=json_mode) if opts.voice not in voices.VOICE_NAMES: raise UsageError( f"Unknown voice {opts.voice!r}.", - suggestion="Run 'assembly agent-framework --list-voices' to see the options.", + suggestion="Run 'assembly agent-cascade --list-voices' to see the options.", ) # Streaming TTS has no production host, so the whole cascade is sandbox-only. - tts_session.require_available("agent-framework") + tts_session.require_available("agent-cascade") system_prompt_text = _resolve_system_prompt(opts.system_prompt, opts.system_prompt_file) from_file = bool(opts.source) or opts.sample diff --git a/aai_cli/init/templates/__init__.py b/aai_cli/init/templates/__init__.py index 3fa4dcd5..ee336ac2 100644 --- a/aai_cli/init/templates/__init__.py +++ b/aai_cli/init/templates/__init__.py @@ -9,7 +9,7 @@ "audio-transcription": "Audio Transcription", "live-captions": "Live Captions", "voice-agent": "Voice Agent", - "agent-framework": "Agent Framework", + "agent-cascade": "Agent Cascade", } # Display order for the picker and `--help`. @@ -17,7 +17,7 @@ "audio-transcription", "live-captions", "voice-agent", - "agent-framework", + "agent-cascade", ) @@ -27,7 +27,7 @@ "audio-transcription": "Transcribe audio & video files, URLs, and YouTube — speaker labels and audio intelligence", "live-captions": "Live real-time captions from your microphone over the Streaming API", "voice-agent": "Full-duplex voice agent (speech in, LLM reply, speech out) via the Voice Agent API", - "agent-framework": "Cascaded voice agent you orchestrate: Streaming STT, the LLM Gateway, and sandbox TTS", + "agent-cascade": "Cascaded voice agent you orchestrate: Streaming STT, the LLM Gateway, and sandbox TTS", } diff --git a/aai_cli/init/templates/agent_framework/AGENTS.md b/aai_cli/init/templates/agent_cascade/AGENTS.md similarity index 100% rename from aai_cli/init/templates/agent_framework/AGENTS.md rename to aai_cli/init/templates/agent_cascade/AGENTS.md diff --git a/aai_cli/init/templates/agent_framework/Dockerfile b/aai_cli/init/templates/agent_cascade/Dockerfile similarity index 100% rename from aai_cli/init/templates/agent_framework/Dockerfile rename to aai_cli/init/templates/agent_cascade/Dockerfile diff --git a/aai_cli/init/templates/agent_framework/Procfile b/aai_cli/init/templates/agent_cascade/Procfile similarity index 100% rename from aai_cli/init/templates/agent_framework/Procfile rename to aai_cli/init/templates/agent_cascade/Procfile diff --git a/aai_cli/init/templates/agent_framework/README.md b/aai_cli/init/templates/agent_cascade/README.md similarity index 94% rename from aai_cli/init/templates/agent_framework/README.md rename to aai_cli/init/templates/agent_cascade/README.md index 019152a1..93e1ea12 100644 --- a/aai_cli/init/templates/agent_framework/README.md +++ b/aai_cli/init/templates/agent_cascade/README.md @@ -1,4 +1,4 @@ -# Talk to a cascaded voice agent — AssemblyAI agent-framework starter +# Talk to a cascaded voice agent — AssemblyAI agent-cascade starter Click connect and talk. Unlike the `voice-agent` template (which uses AssemblyAI's all-in-one Voice Agent API), this app is a **cascade your own backend orchestrates**: @@ -12,7 +12,7 @@ Streaming TTS has no production host, so the whole cascade runs against the Asse sandbox with a sandbox key. Scaffold it that way: ```sh -assembly --sandbox init agent-framework +assembly --sandbox init agent-cascade ``` That pins the sandbox hosts in `.env`. Running against production exits with a hint. diff --git a/aai_cli/init/templates/agent_framework/__init__.py b/aai_cli/init/templates/agent_cascade/__init__.py similarity index 100% rename from aai_cli/init/templates/agent_framework/__init__.py rename to aai_cli/init/templates/agent_cascade/__init__.py diff --git a/aai_cli/init/templates/agent_framework/api/__init__.py b/aai_cli/init/templates/agent_cascade/api/__init__.py similarity index 100% rename from aai_cli/init/templates/agent_framework/api/__init__.py rename to aai_cli/init/templates/agent_cascade/api/__init__.py diff --git a/aai_cli/init/templates/agent_framework/api/cascade.py b/aai_cli/init/templates/agent_cascade/api/cascade.py similarity index 99% rename from aai_cli/init/templates/agent_framework/api/cascade.py rename to aai_cli/init/templates/agent_cascade/api/cascade.py index 5c41bca3..5f8d2dc1 100644 --- a/aai_cli/init/templates/agent_framework/api/cascade.py +++ b/aai_cli/init/templates/agent_cascade/api/cascade.py @@ -1,4 +1,4 @@ -"""Server-side cascade orchestrator for the agent-framework template. +"""Server-side cascade orchestrator for the agent-cascade template. The browser opens one WebSocket to FastAPI and the backend wires three AssemblyAI primitives together — Streaming STT, the LLM Gateway, and streaming TTS — so every @@ -63,7 +63,7 @@ def unavailable_reason(settings: _Settings) -> str | None: if not settings.TTS_HOST: return ( "Streaming TTS has no production host, so this cascade is sandbox-only. " - "Re-scaffold against the sandbox: assembly --sandbox init agent-framework." + "Re-scaffold against the sandbox: assembly --sandbox init agent-cascade." ) return None diff --git a/aai_cli/init/templates/agent_framework/api/index.py b/aai_cli/init/templates/agent_cascade/api/index.py similarity index 89% rename from aai_cli/init/templates/agent_framework/api/index.py rename to aai_cli/init/templates/agent_cascade/api/index.py index f65a6990..f72f52c2 100644 --- a/aai_cli/init/templates/agent_framework/api/index.py +++ b/aai_cli/init/templates/agent_cascade/api/index.py @@ -1,9 +1,9 @@ -"""Talk to a cascaded voice agent — AssemblyAI agent-framework starter (FastAPI). +"""Talk to a cascaded voice agent — AssemblyAI agent-cascade starter (FastAPI). The browser opens one WebSocket to this backend, which runs the cascade itself — Streaming STT -> LLM Gateway -> streaming TTS — so your API key never reaches the client. Streaming TTS is sandbox-only, so scaffold with `assembly --sandbox init -agent-framework` and use a sandbox key. +agent-cascade` and use a sandbox key. WS /ws <- {"type":"input.audio","audio":} ; -> transcripts + reply.audio """ diff --git a/aai_cli/init/templates/agent_framework/api/settings.py b/aai_cli/init/templates/agent_cascade/api/settings.py similarity index 100% rename from aai_cli/init/templates/agent_framework/api/settings.py rename to aai_cli/init/templates/agent_cascade/api/settings.py diff --git a/aai_cli/init/templates/agent_framework/dockerignore b/aai_cli/init/templates/agent_cascade/dockerignore similarity index 100% rename from aai_cli/init/templates/agent_framework/dockerignore rename to aai_cli/init/templates/agent_cascade/dockerignore diff --git a/aai_cli/init/templates/agent_framework/env.example b/aai_cli/init/templates/agent_cascade/env.example similarity index 81% rename from aai_cli/init/templates/agent_framework/env.example rename to aai_cli/init/templates/agent_cascade/env.example index 6a119b9e..fa30178a 100644 --- a/aai_cli/init/templates/agent_framework/env.example +++ b/aai_cli/init/templates/agent_cascade/env.example @@ -1,6 +1,6 @@ ASSEMBLYAI_API_KEY=your_assemblyai_api_key_here # This cascade uses streaming TTS, which is sandbox-only — use a sandbox key and the -# sandbox hosts (assembly --sandbox init agent-framework fills these in for you): +# sandbox hosts (assembly --sandbox init agent-cascade fills these in for you): # ASSEMBLYAI_STREAMING_HOST=streaming.sandbox000.assemblyai-labs.com # ASSEMBLYAI_TTS_HOST=streaming-tts.sandbox000.assemblyai-labs.com # ASSEMBLYAI_LLM_GATEWAY_URL=https://llm-gateway.sandbox000.assemblyai-labs.com/v1 diff --git a/aai_cli/init/templates/agent_framework/gitignore b/aai_cli/init/templates/agent_cascade/gitignore similarity index 100% rename from aai_cli/init/templates/agent_framework/gitignore rename to aai_cli/init/templates/agent_cascade/gitignore diff --git a/aai_cli/init/templates/agent_framework/requirements.txt b/aai_cli/init/templates/agent_cascade/requirements.txt similarity index 100% rename from aai_cli/init/templates/agent_framework/requirements.txt rename to aai_cli/init/templates/agent_cascade/requirements.txt diff --git a/aai_cli/init/templates/agent_framework/runtime.txt b/aai_cli/init/templates/agent_cascade/runtime.txt similarity index 100% rename from aai_cli/init/templates/agent_framework/runtime.txt rename to aai_cli/init/templates/agent_cascade/runtime.txt diff --git a/aai_cli/init/templates/agent_framework/static/app.js b/aai_cli/init/templates/agent_cascade/static/app.js similarity index 100% rename from aai_cli/init/templates/agent_framework/static/app.js rename to aai_cli/init/templates/agent_cascade/static/app.js diff --git a/aai_cli/init/templates/agent_framework/static/audio.js b/aai_cli/init/templates/agent_cascade/static/audio.js similarity index 100% rename from aai_cli/init/templates/agent_framework/static/audio.js rename to aai_cli/init/templates/agent_cascade/static/audio.js diff --git a/aai_cli/init/templates/agent_framework/static/index.html b/aai_cli/init/templates/agent_cascade/static/index.html similarity index 100% rename from aai_cli/init/templates/agent_framework/static/index.html rename to aai_cli/init/templates/agent_cascade/static/index.html diff --git a/aai_cli/init/templates/agent_framework/static/styles.css b/aai_cli/init/templates/agent_cascade/static/styles.css similarity index 100% rename from aai_cli/init/templates/agent_framework/static/styles.css rename to aai_cli/init/templates/agent_cascade/static/styles.css diff --git a/aai_cli/init/templates/agent_framework/vercel.json b/aai_cli/init/templates/agent_cascade/vercel.json similarity index 100% rename from aai_cli/init/templates/agent_framework/vercel.json rename to aai_cli/init/templates/agent_cascade/vercel.json diff --git a/tests/__snapshots__/test_snapshots_help_build.ambr b/tests/__snapshots__/test_snapshots_help_build.ambr index 14447ca7..c2671f11 100644 --- a/tests/__snapshots__/test_snapshots_help_build.ambr +++ b/tests/__snapshots__/test_snapshots_help_build.ambr @@ -89,7 +89,7 @@ ╭─ Arguments ──────────────────────────────────────────────────────────────────╮ │ template [TEMPLATE] Template to scaffold: audio-transcription, │ - │ live-captions, voice-agent, agent-framework │ + │ live-captions, voice-agent, agent-cascade │ │ (omit to pick interactively) │ │ directory [DIRECTORY] Target directory (default: