Skip to content

feat: add graceful stop method to run_async#5559

Open
BowedMars2 wants to merge 18 commits intogoogle:mainfrom
BowedMars374878:Issue-#4796
Open

feat: add graceful stop method to run_async#5559
BowedMars2 wants to merge 18 commits intogoogle:mainfrom
BowedMars374878:Issue-#4796

Conversation

@BowedMars2
Copy link
Copy Markdown
Contributor

@BowedMars2 BowedMars2 commented Apr 30, 2026

Link to Issue or Description of Change

Link to an existing issue (if applicable):

Problem:
There is currently no graceful way of stopping run_async. The current method is essentially a workaround, and there are multiple issues with it, including the inability to tell it was interrupted.

Solution:
My solution adds an optional stop_signal field to run_async, which can be externally triggered to tell run_async to stop after the next returned Event.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required
for all PRs that are not small documentation or typo fixes.

Unit Tests:

  • [✓] I have added or updated unit tests for my change.
  • [✓] All unit tests pass locally.

Please include a summary of passed pytest results.

Manual End-to-End (E2E) Tests:

To manually test my code, I created a test agent:

from google.adk.agents.llm_agent import Agent

root_agent = Agent(
    model='gemini-3-flash-preview',
    name='root_agent',
    description="A helpful assistant for user questions.",
    instruction="Answer any user question to the best of your knowledge."
)

I then created another file that asks the agent to write a long story, then stops it after a few seconds. This uses the SSE streaming mode, so that events contain clumps of generated text rather than sending the entire story all at once at the end.

import asyncio
from dotenv import load_dotenv
import agent
from google.adk.runners import InMemoryRunner
from google.adk.agents.run_config import RunConfig
from google.adk.agents.run_config import StreamingMode
from google.adk.runners import StopSignal
from google.genai.types import Part, Content

load_dotenv()

APP_NAME = "adk_test_app"
USER_ID = "adk_test_user"
STOP_SIGNAL = StopSignal()

async def consume_stream(runner, **kwargs):
    async for event in runner.run_async(**kwargs):
        content = ""
        if hasattr(event, 'text'):
            content = event.text
        elif hasattr(event, 'content') and event.content.parts:
            content = event.content.parts[0].text

        if event.interrupted:
            print('Runner interrupted')
        if content:
            print(content)

async def manual_test_interrupt():
    client = agent.root_agent
    runner = InMemoryRunner(agent=client, app_name=APP_NAME)
    
    session = await runner.session_service.create_session(
        app_name=APP_NAME, user_id=USER_ID
    )

    message = Content(
        role="user",
        parts=[Part(text="Generate a long story...")]
    )
    
    print("Starting run_async")
    
    task = asyncio.create_task(consume_stream(
        runner=runner, 
        session_id=session.id, 
        user_id=USER_ID, 
        new_message=message, 
        stop_signal=STOP_SIGNAL,
        run_config=RunConfig(streaming_mode=StreamingMode.SSE)
    ))

    # Wait for a few seconds to let it start generating text
    await asyncio.sleep(5) 
    
    # Interrupts the run
    STOP_SIGNAL.stop()
    
    try:
        # Checks to make sure the task is actually ending
        # This should print immediately after "Runner interrupted"
        await asyncio.wait_for(task, timeout=10)
        print("run_async complete")
    except asyncio.TimeoutError:
        print("Fail: took more than 10 seconds for the runner to stop")

asyncio.run(manual_test_interrupt())

As expected, the agent began generating a story, but was cut off in the middle. Note: during some tests the agent took a while to begin writing the story and I had to adjust the number of seconds it waited before sending the StopSignal.

Checklist

  • [✓] I have read the CONTRIBUTING.md document.
  • [✓] I have performed a self-review of my own code.
  • [✓] I have commented my code, particularly in hard-to-understand areas.
  • [✓] I have added tests that prove my fix is effective or that my feature works.
  • [✓] New and existing unit tests pass locally with my changes.
  • [✓] I have manually tested my changes end-to-end.
  • [✓] Any dependent changes have been merged and published in downstream modules.

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Apr 30, 2026
@rohityan rohityan self-assigned this Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Stop generating" — ability to stop run_async() from outside the agent

3 participants