Feature Request: Run Cancellation / Abort Support for Java ADK
- Dominant language
- Java
- Stars
- 1.7k
- Forks
- 420
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 31
Description
## Summary
Java ADK currently lacks a mechanism to cancel/abort a running agent invocation. TypeScript ADK already ships mature `AbortSignal`-based cancellation ([docs/runtime/cancel.md](https://google.github.io/adk-docs/runtime/cancel/)), and Python ADK has active work in progress (google/adk-python#4825, google/adk-python#5983). **Java ADK has no equivalent — no API, no internal checkpoints, and no graceful shutdown path.**
## Motivation
Cancellation is essential for production agent deployments:
- **User-facing "Stop" button** — long-running multi-tool loops need immediate, graceful termination when the user clicks stop.
- **Timeout enforcement** — server-side request deadlines (e.g., HTTP gateway timeouts) must propagate into the agent execution.
- **Resource cleanup** — without cooperative cancellation, in-flight LLM streaming connections and tool executions leak resources.
- **Cost control** — aborting early avoids unnecessary LLM token consumption.
## Current State
| Language | Status | Mechanism |
|----------|--------|-----------|
| **TypeScript** | ✅ Shipped | `runner.runAsync(params, { signal })` with `AbortSignal`; checkpoints in LLM call, tool execution, and plugin callbacks; graceful generator completion (no throw) |
| **Python** | 🚧 In progress | google/adk-python#4825 (`stop_event: asyncio.Event`), google/adk-python#5983 (`/cancel` API + `task.cancel()`) |
| **Java** | ❌ Missing | Only `InvocationContext.endInvocation` (internal flag, not externally triggerable); `Disposable.dispose()` is a hard RxJava cut (not graceful, tools don't check it); no `RunConfig` timeout/cancel field |
## Proposed Design (aligned with TypeScript)
### API Surface
```java
// Option A: CancellationToken (similar to .NET / structured concurrency)
CancellationTokenSource cts = new CancellationTokenSource();
RunConfig config = RunConfig.builder()
.cancellationToken(cts.token())
.build();
Flowable events = runner.runAsync(userId, sessionId, content, config);
// Later:
cts.cancel(); // triggers graceful shutdown
// Option B: RxJava-native (Disposable already exists, but needs cooperative checks)
// Enhance internal checkpoints to check subscription disposal state
```
### Internal Checkpoints (minimum)
Following TypeScript's lead, cancellation should be checked at:
1. **Before each LLM call** — `BaseLlmFlow.runOneStep()` (already checks `endInvocation`, easy to extend)
2. **Before each tool execution** — `Functions.handleFunctionCalls()` (**currently has NO cancellation check**)
3. **During LLM streaming** — between chunks (for long generations)
4. **Plugin/callback boundaries** — `beforeModel` / `afterModel` / `beforeTool` / `afterTool`
### Semantics (align with TypeScript `cancel.md`)
- **Graceful**: the Flowable completes normally (no error signal), already-emitted events are preserved in the session.
- **Cooperative**: cancellation is checked at defined points; in-flight atomic operations (single LLM call, single tool run) may complete before the next checkpoint.
- **Idempotent**: calling cancel multiple times is safe.
## Questions for Maintainers
1. **API preference**: `CancellationToken` (explicit, testable) vs. leveraging RxJava `Disposable` semantics (less new API surface but less portable)?
2. **Scope**: Should cancellation also cover `runLive` (streaming/live mode), or start with `runAsync` only?
3. **Event emission on cancel**: Should the framework emit a final "cancelled" event (like Python's `temp:cancelled` state proposal), or just complete silently (like TypeScript)?
## References
- TypeScript ADK cancel docs: https://google.github.io/adk-docs/runtime/cancel/
- Python ADK cancellation PR: google/adk-python#4825
- Python ADK `/cancel` API PR: google/adk-python#5983
- Python ADK cancellation discussion: google/adk-python#4156
---
I'm happy to contribute the implementation once the API direction is agreed upon. I have production experience implementing cooperative cancellation in a Java ADK-based agent platform (checkpoint-based, with checks at beforeModel/beforeTool/afterEvent boundaries).
Contributor guide
Assessment
This issue has not been assessed yet.