Use create_transport to simplify bot()#91
Merged
Conversation
Adds a 'headless text-eval transport' option (new init question, default yes) for cascade bots that use the match/case entry point. When enabled, the generated bot.py gains an EvalRunnerArguments case that builds the EvalTransport via create_transport, so the bot can be driven over stdin with 'bot.py -t eval' or programmatically via run_eval — no audio, client, or server. Daily PSTN / Twilio+SIP flows (separate template branch) are excluded. Eval imports are emitted in the template for now since EvalRunnerArguments isn't in a released pipecat yet; move them into FEATURE_DEFINITIONS once it ships.
Point 2: extract supports_eval_transport(config) so the question's gating (cascade + non-PSTN/SIP) reads clearly instead of an inline set expression. Point 3: move the eval imports out of the template and into the registry — add an 'eval' entry to FEATURE_DEFINITIONS, resolve its symbols via _MODULE_OVERRIDES (so regeneration doesn't depend on the searched source tree having them), wire features['eval'] through get_imports_for_services and the bot generator, and regenerate _imports.py. The template no longer hardcodes the eval imports; EvalRunnerArguments now merges into the existing runner.types import line.
The eval transport option was only reachable via the interactive wizard, which hangs automated/agent runs. Add --eval-transport/--no-eval-transport (default on) to the non-interactive init path: thread it through validate_and_build_config, config_to_json, and the JSON config file. The flag is clamped off via supports_eval_transport for configs that can't use it (realtime, Daily PSTN / Twilio+SIP).
Collapse the per-transport match/case boilerplate in generated bots to a single transport_params dict + create_transport, and standardize run_bot to one signature. Only dial-out and SIP keep a bespoke flow (room/token + dial-out settings arrive in the request body, built by server.py). - Templates: bot() builds transports via `await create_transport( runner_args, transport_params)`; delete the now-unused per-transport bot_entry blocks (daily_webrtc, smallwebrtc, websocket, twilio, telnyx, plivo, exotel). - Eval everywhere: drop the --eval-transport flag and the per-bot EvalTransportParams entry/import; `-t eval` builds the EvalTransport through create_transport's defaults. Add an "eval" factory to customize. - Collapse Daily PSTN dial-in onto create_transport (it arrives as a typed DailyRunnerArguments and the framework applies its dial-in body); trim its registry imports to DailyParams. - Standardize run_bot(transport, runner_args) across cascade/realtime and the bespoke dial-out/SIP entries; those parse dialout_settings/request from runner_args.body internally. - Registry: import create_transport for the collapsed path only (dial-out and SIP construct transports by hand); regenerate _imports.py/_configs.py. Update and extend tests (collapsed construction, dial-in collapse, dial-out/SIP bespoke-but-standard-run_bot, uniform run_bot signature).
Align the scaffold's generated personalization with the updated pipecat-examples (twilio/telnyx/exotel/plivo, daily-pstn-dial-in): emit it active (uncommented) with an "optional" note, using the typed CallData / CallInfo attribute API instead of dict access, and without -t eval text (the natural guards keep it eval-safe). - get_call_info macro: return a typed CallInfo model (not a dict), accept call_sid: str | None, return None on failure. - bot_cascade + bot_realtime: active personalization for twilio (get_call_info -> CallInfo), telnyx (call_data.from_number), and daily_pstn_dialin (guarded DailyDialinRequest From/To). Add the twilio/telnyx blocks to bot_realtime too for cascade/realtime parity. - Registry: twilio gains `from pydantic import BaseModel` (CallInfo); daily_pstn_dialin gains `DailyDialinRequest`. Regenerate _imports.py. - Tests: dial-in now expects DailyDialinRequest; add a twilio active- personalization/CallInfo test. Exotel/Plivo unchanged (their examples have no personalization).
The dev runner serves all transports by default and the caller selects which one (a web/mobile client picks its transport via /start; a telephony provider connects to /ws). The -t flag is a restriction, not a requirement, so none of the generated run commands need it: - Telephony: drop `--transport <provider> --proxy ...` (the provider connects to /ws and create_transport auto-detects it; point its webhook at wss://<ngrok>/ws). - Daily: drop `--transport daily` (a Daily client connects via /start). With every transport now running `uv run bot.py`, the per-transport command listing only produced redundant duplicates, so remove _get_run_commands and collapse both the console "Next steps" and the generated README to a single `uv run bot.py` plus a telephony-only ngrok/webhook note.
The generator only runs `ruff format` + `ruff check --select I` (import sorting), so F-rule issues shipped uncaught. Clean the templates and add a generation-time lint guard. Template fixes: - F541: drop the `f` prefix on placeholder-less log strings (handler macros, SIP dial-in server_utils). - F401: LLMRunFrame was imported unconditionally but dial-out bots never queue it (they wait for the callee). Move it from the always-on `runner` feature to its own `llm_run_frame` feature, gated off for dial-out in service_loader. - UP045: Optional[int] -> int | None in DialoutManager; drop the now-unused Optional from the dial-out registry imports. Regenerate the registry. Tests: - Add assert_server_ruff_lint_clean (bundled ruff, --select F) and run it in test_project_generation (all configs) and _gen_bot (dial-in/out/SIP). - This immediately caught a real bug: exotel-cascade used playht_tts, which is not a registered service, so the generator emitted a pipeline referencing an undefined `tts` (F821). Fix the stale config (playht_tts -> rime_tts). All 435 tests pass.
The branch's original headless eval-transport direction was superseded by the create_transport consolidation, so the net diff ships no eval code — only leftover references. Some were also made incorrect by Pipecat's create_transport changes (pipecat-ai/pipecat#4615), which no longer build an EvalTransport through create_transport. - CHANGELOG: replace the "headless text-eval transport" entry with the actual change — generated bots configure transports via create_transport, ship active telephony personalization, and run with a plain `uv run bot.py`. - Drop the now-incorrect "`-t eval` builds it through create_transport" comments in service_loader, service_metadata, import_generator, and the cascade/realtime templates. - De-eval test_project_generation: remove the eval-framed docstring/comments and the assertions checking for the absence of an eval factory / EvalTransportParams.
Contributor
Author
|
@aconchillo and @filipi87 probably less important to review. I think once pipecat-ai/pipecat#4615 merges, I'm going to move the init command into pipecat. Perhaps I'll cut this final release plus add an archive message to the repo. TBD. |
tomllib is always available on the supported Python versions, so the tomli import fallback in the project-generation tests and the matching dev dependency are dead code. uv.lock keeps tomli only as coverage's transitive toml extra.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please describe the changes in your PR.
Simplifies how a scaffolded bot configures its transport. Building on pipecat-ai/pipecat#4615, which makes
create_transportthe single, feature-complete way to build any transport, this collapses the per-transport boilerplate in generated bots onto onecreate_transportcall — and, while the generated bots were being reworked, brings their telephony personalization in line with the updatedpipecat-examples, simplifies the run instructions, and adds a generation-time lint guard.Consolidate transport construction onto
create_transportCollapse the per-transport
match/caseboilerplate in generated bots to a singletransport_paramsdict +await create_transport(runner_args, transport_params), and standardize on onerun_bot(transport, runner_args)signature across cascade and realtime.bot_entry_*blocks (daily_webrtc, smallwebrtc, websocket, twilio, telnyx, plivo, exotel) —create_transporthandles dispatch.create_transporttoo (it arrives as a typedDailyRunnerArgumentsand the framework applies the dial-in body); its registry imports trim toDailyParams.runner_args.body, built byserver.py), but they now share the same standardizedrun_botsignature.Active telephony personalization matching the examples
Align generated personalization with the updated
pipecat-examples— emitted active (uncommented) with an "optional" note, using the typedCallData/CallInfoattribute API instead of dict access:get_call_infomacro now returns a typedCallInfomodel (not a dict), acceptscall_sid: str | None, and returnsNoneon failure.get_call_info→CallInfo), Telnyx (call_data.from_number), and Daily PSTN (guardedDailyDialinRequestFrom/To) blocks — added to bothbot_cascadeandbot_realtimefor parity.Simplify run instructions to
uv run bot.pyThe dev runner serves all transports by default and the caller selects one (
/startfor a web/mobile client,/wsfor a telephony provider), so-tis a restriction, not a requirement. Every generated run command is now justuv run bot.py(telephony adds a one-line ngrok/webhook note pointing the provider atwss://<ngrok>/ws). Removed the redundant per-transport command listing (_get_run_commands) from both the console "Next steps" and the generated README.Generation-time lint guard
The generator only ran
ruff format+ruff check --select I(import sorting), so F-rule issues shipped uncaught. Addedassert_server_ruff_lint_clean(bundled ruff,--select F) across all configs intest_project_generationand_gen_bot. This immediately caught a real bug — exotel-cascade referenced the unregisteredplayht_tts, so the generator emitted a pipeline using an undefinedtts(F821); fixed the stale config torime_tts. Also cleaned F541/F401/UP045 in the templates and splitLLMRunFrameinto its ownllm_run_framefeature (dial-out bots wait for the callee and never queue it).Testing
All 435 tests pass, and generated bots are now asserted ruff-clean (
--select F) at generation time.