Use symmetric spawn-then-run() pattern in multi-task examples

Switch every example to ``await runner.spawn(task)`` followed by
``await runner.run()`` (no task argument), and ``await runner.cancel()``
on client-disconnected instead of ``await task.cancel()``. This makes
the main pipeline task look the same as the worker / proxy tasks
spawned alongside it, and lets ``runner.cancel()`` drive a uniform
shutdown across every root task on the bus.
This commit is contained in:
Aleix Conchillo Flaqué
2026-05-15 08:46:46 -07:00
parent 5f1b91bb89
commit f22350ce2f
6 changed files with 31 additions and 25 deletions

View File

@@ -145,8 +145,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs, idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
) )
await runner.spawn(CodeWorker("code_worker", project_path=PROJECT_PATH))
@transport.event_handler("on_client_connected") @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client): async def on_client_connected(transport, client):
logger.info("Client connected") logger.info("Client connected")
@@ -161,9 +159,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
@transport.event_handler("on_client_disconnected") @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client): async def on_client_disconnected(transport, client):
logger.info("Client disconnected") logger.info("Client disconnected")
await task.cancel() await runner.cancel()
await runner.run(task) await runner.spawn(CodeWorker("code_worker", project_path=PROJECT_PATH))
await runner.spawn(task)
await runner.run()
async def bot(runner_args: RunnerArguments): async def bot(runner_args: RunnerArguments):

View File

@@ -227,9 +227,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs, idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
) )
await runner.spawn(_build_greeter())
await runner.spawn(_build_support())
@transport.event_handler("on_client_connected") @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client): async def on_client_connected(transport, client):
logger.info("Client connected") logger.info("Client connected")
@@ -251,9 +248,13 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
@transport.event_handler("on_client_disconnected") @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client): async def on_client_disconnected(transport, client):
logger.info("Client disconnected") logger.info("Client disconnected")
await task.cancel() await runner.cancel()
await runner.run(task) await runner.spawn(_build_greeter())
await runner.spawn(_build_support())
await runner.spawn(task)
await runner.run()
async def bot(runner_args: RunnerArguments): async def bot(runner_args: RunnerArguments):

View File

@@ -200,11 +200,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs, idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
) )
# Spawn the child LLM tasks. ``bridged=()`` on each child auto-wraps
# its pipeline with bus edges, so no extra wiring is needed here.
await runner.spawn(_build_greeter())
await runner.spawn(_build_support())
@transport.event_handler("on_client_connected") @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client): async def on_client_connected(transport, client):
logger.info("Client connected") logger.info("Client connected")
@@ -226,9 +221,13 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
@transport.event_handler("on_client_disconnected") @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client): async def on_client_disconnected(transport, client):
logger.info("Client disconnected") logger.info("Client disconnected")
await task.cancel() await runner.cancel()
await runner.run(task) await runner.spawn(_build_greeter())
await runner.spawn(_build_support())
await runner.spawn(task)
await runner.run()
async def bot(runner_args: RunnerArguments): async def bot(runner_args: RunnerArguments):

View File

@@ -198,9 +198,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
idle_timeout_secs=runner_args.pipeline_idle_timeout_secs, idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
) )
for role in ROLE_PROMPTS:
await runner.spawn(DebateWorker(role))
@transport.event_handler("on_client_connected") @transport.event_handler("on_client_connected")
async def on_client_connected(transport, client): async def on_client_connected(transport, client):
logger.info("Client connected") logger.info("Client connected")
@@ -218,9 +215,13 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
@transport.event_handler("on_client_disconnected") @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client): async def on_client_disconnected(transport, client):
logger.info("Client disconnected") logger.info("Client disconnected")
await task.cancel() await runner.cancel()
await runner.run(task) for role in ROLE_PROMPTS:
await runner.spawn(DebateWorker(role))
await runner.spawn(task)
await runner.run()
async def bot(runner_args: RunnerArguments): async def bot(runner_args: RunnerArguments):

View File

@@ -104,8 +104,10 @@ async def websocket_endpoint(websocket: WebSocket):
assistant = AcmeAssistant() assistant = AcmeAssistant()
await runner.spawn(proxy) await runner.spawn(proxy)
await runner.spawn(assistant)
logger.info("Assistant server ready, waiting for activation") logger.info("Assistant server ready, waiting for activation")
await runner.run(assistant) await runner.run()
logger.info("Assistant server session ended") logger.info("Assistant server session ended")

View File

@@ -116,7 +116,6 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
remote_task_name="assistant", remote_task_name="assistant",
forward_messages=(BusFrameMessage,), forward_messages=(BusFrameMessage,),
) )
await runner.spawn(proxy)
async def on_assistant_ready(_data: TaskReadyData) -> None: async def on_assistant_ready(_data: TaskReadyData) -> None:
logger.info("Remote assistant ready, activating") logger.info("Remote assistant ready, activating")
@@ -145,9 +144,12 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
@transport.event_handler("on_client_disconnected") @transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client): async def on_client_disconnected(transport, client):
logger.info("Client disconnected") logger.info("Client disconnected")
await task.cancel() await runner.cancel()
await runner.run(task) await runner.spawn(proxy)
await runner.spawn(task)
await runner.run()
async def bot(runner_args: RunnerArguments): async def bot(runner_args: RunnerArguments):