Skip to content

fix(agent): checkpoint state on stream cancellation - #2461

Open
Niooooo wants to merge 1 commit into
agentscope-ai:mainfrom
Niooooo:fix/issue-1997-cancellation-checkpoint
Open

fix(agent): checkpoint state on stream cancellation#2461
Niooooo wants to merge 1 commit into
agentscope-ai:mainfrom
Niooooo:fix/issue-1997-cancellation-checkpoint

Conversation

@Niooooo

@Niooooo Niooooo commented Jul 28, 2026

Copy link
Copy Markdown

AgentScope-Java Version

2.0.1-SNAPSHOT

Description

Fixes #1997.

Background

When a streamEvents(...) subscription is cancelled, such as after an SSE
disconnect, the normal completion-based persistence path is not reached. The
live per-call AgentState may therefore be cleaned up without a timely
checkpoint, making intermediate context, summary, task, plan, tool, and
subagent state unrecoverable.

Changes

  • Capture the exact per-call scope after it has been established.
  • Trigger a best-effort checkpoint when the call receives a downstream
    cancellation signal.
  • Reuse the existing CallExecution and session persistence path so the
    correct (userId, sessionId, agent_state) is saved.
  • Keep the same-session serialization gate closed until cancellation
    persistence terminates, preventing a newer call from loading stale state or
    being overwritten by an older delayed save.
  • Preserve concurrency between different sessions.
  • Keep lifecycle cleanup, sandbox release, shutdown unregister, and session
    gate release safe when persistence fails.
  • Keep cancellation safe when no AgentStateStore is configured.
  • Avoid duplicate persistence on normal completion.
  • Add unit tests covering cancellation persistence, complete state recovery,
    normal completion, missing stores, persistence failures, same-session
    ordering, and cross-session isolation.
  • Document cancellation checkpoint behavior in the English and Chinese
    context documentation.

Testing

  • ReActAgentCancellationCheckpointTest: 5/5 passed.
  • DangerousPathBypassTest: 9/9 passed when rerun with the required Windows
    symbolic-link privilege.
  • GracefulShutdownTest: 46/46 passed in isolation.
  • Project-wide clean verify completed successfully across all 82 reactor
    modules, with the Windows privilege-dependent and shared-state
    order-sensitive test classes verified separately as listed above.
  • Spotless validation passed.
  • Javadoc generation and doclint validation passed.

Checklist

Please check the following items before code is ready to be reviewed.

  • Code formatting passes the project Spotless checks
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.)
  • Code is ready for review

@CLAassistant

CLAassistant commented Jul 28, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.70588% with 18 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../main/java/io/agentscope/core/agent/AgentBase.java 64.44% 15 Missing and 1 partial ⚠️
...e/src/main/java/io/agentscope/core/ReActAgent.java 66.66% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@oss-maintainer oss-maintainer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: PR #2461 — checkpoint state on stream cancellation

Verdict: Approve ✅

Summary

Fixes a real data-loss scenario: when streamEvents() is cancelled (e.g., SSE disconnect), the normal completion-based persistence path is bypassed, leaving intermediate agent state unrecoverable. This PR adds a cancellation-triggered checkpoint mechanism.

Changes Analyzed

File Assessment
AgentBase.java (+103/-10) Core cancellation hook — captures callScope via AtomicReference, hooks into reactive cancellation signals, triggers onAgentExecutionCancelled(). Session serialization gate properly held until checkpoint completes.
ReActAgent.java (+15) Clean override — delegates to saveStateToSession(), errors logged but swallowed to avoid breaking the cancellation flow.
ReActAgentCancellationCheckpointTest.java (+416) Thorough coverage: normal cancel, full state recovery, missing store, persistence failure, same-session ordering, cross-session isolation.
context.md (EN/ZH) Concise documentation of cancellation checkpoint behavior.

Strengths

  1. Correct concurrency model — Same-session calls serialized behind the cancellation checkpoint; cross-session calls proceed independently.
  2. Best-effort semantics — Checkpoint failures logged but don't propagate, preventing cascade failures.
  3. No duplicate persistence — Normal completion path preserved; cancellation hook only fires on actual cancel signals.
  4. Comprehensive testing — 5 test scenarios with proper CountDownLatch synchronization for timing-sensitive behavior.
  5. Clean abstractiononAgentExecutionCancelled(Object callScope) is a protected hook allowing other agent implementations to opt in.

Minor Observations (non-blocking)

  1. The callScope AtomicReference pattern is correct but slightly unusual — a brief inline comment explaining the data flow would help future maintainers.
  2. Consider whether doFinally with SignalType.CANCEL is more idiomatic than the current doOnCancel + doFinally combination.

Neither observation warrants changes. Solid implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]:streamEvents cancellation does not guarantee AgentState checkpoint for resumable sessions

3 participants