feat: 支持 Agent 运行刷新恢复

- 解耦 Runtime 与浏览器 SSE 订阅并增加 Redis 游标日志

- 支持正式聊天与草稿试运行刷新重连和权威终态恢复

- 完善显式取消、owner 丢失、容量限制与故障测试
This commit is contained in:
2026-08-20 11:18:10 +08:00
parent 310fc1fb58
commit fa07134cf8
36 changed files with 4876 additions and 322 deletions

View File

@@ -72,6 +72,21 @@ public class AgentRuntimeProperties {
*/
private Duration asyncToolTaskTtl = Duration.ofHours(24);
/**
* AG-UI 可重连运行事件保留时间。
*/
private Duration aguiRunRetention = Duration.ofHours(24);
/**
* AG-UI 事件日志批量刷入 Redis 的间隔。
*/
private Duration aguiJournalFlushInterval = Duration.ofMillis(50);
/**
* AG-UI 重连订阅轮询 Redis 的间隔。
*/
private Duration aguiReplayPollInterval = Duration.ofMillis(100);
/**
* 获取 Redis 热态 session 缓存 TTL。
*
@@ -90,6 +105,60 @@ public class AgentRuntimeProperties {
this.sessionCacheTtl = sessionCacheTtl == null ? Duration.ofHours(24) : sessionCacheTtl;
}
/**
* 获取 AG-UI 可重连运行事件保留时间。
*
* @return 事件保留时间
*/
public Duration getAguiRunRetention() {
return aguiRunRetention;
}
/**
* 设置 AG-UI 可重连运行事件保留时间。
*
* @param aguiRunRetention 事件保留时间
*/
public void setAguiRunRetention(Duration aguiRunRetention) {
this.aguiRunRetention = positiveDuration(aguiRunRetention, Duration.ofHours(24));
}
/**
* 获取 AG-UI 事件日志批量刷入 Redis 的间隔。
*
* @return 刷盘间隔
*/
public Duration getAguiJournalFlushInterval() {
return aguiJournalFlushInterval;
}
/**
* 设置 AG-UI 事件日志批量刷入 Redis 的间隔。
*
* @param aguiJournalFlushInterval 刷盘间隔
*/
public void setAguiJournalFlushInterval(Duration aguiJournalFlushInterval) {
this.aguiJournalFlushInterval = positiveDuration(aguiJournalFlushInterval, Duration.ofMillis(50));
}
/**
* 获取 AG-UI 重连订阅轮询 Redis 的间隔。
*
* @return 轮询间隔
*/
public Duration getAguiReplayPollInterval() {
return aguiReplayPollInterval;
}
/**
* 设置 AG-UI 重连订阅轮询 Redis 的间隔。
*
* @param aguiReplayPollInterval 轮询间隔
*/
public void setAguiReplayPollInterval(Duration aguiReplayPollInterval) {
this.aguiReplayPollInterval = positiveDuration(aguiReplayPollInterval, Duration.ofMillis(100));
}
/**
* 获取当前 Agent 运行实例 ID。
*
@@ -281,6 +350,10 @@ public class AgentRuntimeProperties {
this.asyncToolTaskTtl = asyncToolTaskTtl == null ? Duration.ofHours(24) : asyncToolTaskTtl;
}
private static Duration positiveDuration(Duration value, Duration fallback) {
return value == null || value.isZero() || value.isNegative() ? fallback : value;
}
private static String defaultInstanceId() {
String envInstanceId = System.getenv("EASYFLOW_INSTANCE_ID");
if (StringUtils.hasText(envInstanceId)) {