Skip to content

fix(core): persist state on call cancellation - #2820

Open
hanydd wants to merge 1 commit into
agentscope-ai:mainfrom
hanydd:fix/cancelled-call-state
Open

fix(core): persist state on call cancellation#2820
hanydd wants to merge 1 commit into
agentscope-ai:mainfrom
hanydd:fix/cancelled-call-state

Conversation

@hanydd

@hanydd hanydd commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

AgentScope-Java Version

2.0.3-SNAPSHOT

Description

背景

#2799 已在模型调用报错时保存安全的对话状态,但 Reactor cancellation 不会进入异常处理,因此取消普通或 structured-output 调用时,本轮用户输入仍可能丢失。

另外,如果 reasoning 已经提交了 tool call,而 acting 或 middleware 在写入 tool result 前报错,直接保存会留下没有结果的 PENDING tool call。

本 PR 是 #2713 基于 #2799 的精简后续,只补充上述两个场景。

改动

  • 普通、native structured-output 和 fallback structured-output 调用被取消时,尽力保存当前安全状态。
  • 复用 fix(agent): 模型调用失败时持久化当前轮次上下文 #2799 的报错保存流程;异常保存前只删除本轮没有结果的 PENDING tool call。
  • 不保存未完成的 assistant 流式片段,不修改 public API 或 Session schema。

测试

  • mvn -pl agentscope-core -Dtest=ReActAgentCallFailurePersistenceTest test
  • mvn -pl agentscope-core test

2298 tests passed,8 skipped。

Checklist

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (no documentation change required)
  • Code is ready for review

@hanydd
hanydd force-pushed the fix/cancelled-call-state branch from 3a7d8c5 to e1ca130 Compare August 24, 2026 00:21
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.11111% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...e/src/main/java/io/agentscope/core/ReActAgent.java 71.11% 7 Missing and 6 partials ⚠️

📢 Thoughts on this report? Let us know!

@guslegend0510 guslegend0510 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

审查发现了两个会影响取消状态正确性的真实问题,不适合直接批准

Comment on lines +2167 to +2170
!(block instanceof ToolUseBlock toolUse)
|| toolUse.getState()
!= ToolCallState.PENDING
|| !pendingIds.contains(toolUse.getId()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] ALLOWED 工具调用未被清理

acting 在执行工具前会把调用改为 ALLOWED,因此工具执行中取消或 acting 后置失败时,这里的 PENDING 条件会保留一个没有 tool_result 的 tool_use。默认 pending recovery 关闭,下一轮普通调用会失败,空消息恢复还可能重复执行工具。应清理本轮无结果的 PENDING/ALLOWED,并保留 ASKING。

.ifPresent(ae -> scope.externalEventEmitter = ae);
}
return scope.doCallInner(msgs)
.doOnCancel(() -> saveStateAfterCancellation(scope))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] 取消前同步保存会阻塞并竞态双写

doOnCancel 回调先同步持久化、随后才向上游传播 cancel,阻塞式状态库会延迟模型和工具停止,并允许 live state 在保存时继续变化;取消发生在正常异步保存期间时还会启动第二次 persistState,造成 loadedVersion/CAS 竞态。应统一为单一的取消终止保存流程,在上游取消后保存稳定快照。

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.

2 participants