说明:本描述已于 2026-09-17 修订。初版把 0.1.15 → 0.1.16 称作「patch 版本」并据此建议调整版本号方案,这个判断是错的——本仓库只有 0.1.x 一条线,第三位就是正常的发布递进位,真正的补丁走 .postN(0.1.13.post1、0.1.14.post1/post2)。相关段落已删除。本 issue 现在只针对一处零成本可修的兼容性细节。
问题
com.openjiuwen.core.singleagent.interrupt.ToolInterruptEntry 在 0.1.15 → 0.1.16 之间丢失了 2 参构造器。
该类新增第三个字段 settledDecisions(javadoc 标注 @since 0.1.16,来源应为 #163 中断重放缺少已判定事实)。类上有 Lombok @AllArgsConstructor,字段数变化直接改写全参构造器签名,原 2 参版本随之消失:
# 0.1.15(javap 反编译)
public ToolInterruptEntry();
public ToolInterruptEntry(ToolCall, InterruptRequest);
# 0.1.16
public ToolInterruptEntry();
public ToolInterruptEntry(ToolCall, InterruptRequest, java.util.List<RailSettledDecision>);
settledDecisions 本身的设计没有问题,#163 的需求也是合理的。本 issue 只针对它附带的这处兼容性副作用。
为什么这个破坏很难被察觉
上游自身从未调用过这个构造器。 在 930 分支与 v0.1.15 标签上全仓搜索 new ToolInterruptEntry( 均无命中,内部一律走 builder。也就是说字段新增时,仓内没有任何调用点会编译失败,CI 也不会给出信号——破坏只在下游显现。
加上 settledDecisions 带 @Builder.Default(默认空列表),语义上也不存在「必须强制调用方显式传入」的设计动机。综合这两点,我们判断这次签名变更是 @AllArgsConstructor 的副作用,而非有意收紧 API。如果实际上是有意为之,烦请在此说明,我们在下游按新签名适配即可,本 issue 可以直接关闭。
下游影响
凡以 2 参形式构造该对象的代码,升级到 0.1.16 后编译失败:
no suitable constructor found for ToolInterruptEntry(
com.openjiuwen.core.foundation.llm.schema.ToolCall,
com.openjiuwen.core.singleagent.interrupt.InterruptRequest)
agent-solution 仓有 4 处这样的调用(均在 edp-agent-engine 的测试代码中),已改为 builder 形式适配完毕,故对我们不构成阻塞。提出本 issue 是因为:由于是构造器签名变更而非类删除,类清单比对无法发现它,只在编译期暴露;对已编译的下游产物还会表现为运行期 NoSuchMethodError。后续其他使用方可能重复踩到。
补充一个范围数据供参考:我们对 0.1.15 与 0.1.16 两个正式发布 jar 的 com.openjiuwen.core.* 全部 963 个公开类做了构造器签名逐一比对(两种实现独立跑出同一结果),构造器丢失的类只有 ToolInterruptEntry 一个,同区间 core jar 的类移除数为 0。所以这是个例,不是普遍做法。
复现
// 依赖 agent-core-java 0.1.15
ToolCall call = ToolCall.builder().id("x").name("y").build();
InterruptRequest req = InterruptRequest.builder().build();
new ToolInterruptEntry(call, req); // 0.1.15 编译通过
// 依赖改为 0.1.16 → 编译失败
建议
补一个 2 参构造器委托,与 builder 省略该字段时语义等价:
public ToolInterruptEntry(ToolCall toolCall, InterruptRequest request) {
this(toolCall, request, new ArrayList<>());
}
两行,不改变任何既有行为,0.1.15 的调用方无需改动即可升级。
如果希望从根上避免同类问题再次发生,可以考虑给这类可演进的 DTO 停用 @AllArgsConstructor(或改为 @AllArgsConstructor(access = AccessLevel.PRIVATE)),只对外暴露 @Builder + @NoArgsConstructor——builder 天然对新增字段免疫,而 @AllArgsConstructor 会把「加字段」这个通常向后兼容的动作变成签名变更。这一条属于可选的长期改进,不影响本 issue 的处理。
环境
agent-core-java 0.1.15 → 0.1.16(930 分支,a2549228b)
- 下游:
agent-solution / common 分支,JDK 21,Maven 3.8.7
问题
com.openjiuwen.core.singleagent.interrupt.ToolInterruptEntry在0.1.15 → 0.1.16之间丢失了 2 参构造器。该类新增第三个字段
settledDecisions(javadoc 标注@since 0.1.16,来源应为 #163 中断重放缺少已判定事实)。类上有 Lombok@AllArgsConstructor,字段数变化直接改写全参构造器签名,原 2 参版本随之消失:settledDecisions本身的设计没有问题,#163 的需求也是合理的。本 issue 只针对它附带的这处兼容性副作用。为什么这个破坏很难被察觉
上游自身从未调用过这个构造器。 在
930分支与v0.1.15标签上全仓搜索new ToolInterruptEntry(均无命中,内部一律走 builder。也就是说字段新增时,仓内没有任何调用点会编译失败,CI 也不会给出信号——破坏只在下游显现。加上
settledDecisions带@Builder.Default(默认空列表),语义上也不存在「必须强制调用方显式传入」的设计动机。综合这两点,我们判断这次签名变更是@AllArgsConstructor的副作用,而非有意收紧 API。如果实际上是有意为之,烦请在此说明,我们在下游按新签名适配即可,本 issue 可以直接关闭。下游影响
凡以 2 参形式构造该对象的代码,升级到 0.1.16 后编译失败:
agent-solution仓有 4 处这样的调用(均在edp-agent-engine的测试代码中),已改为 builder 形式适配完毕,故对我们不构成阻塞。提出本 issue 是因为:由于是构造器签名变更而非类删除,类清单比对无法发现它,只在编译期暴露;对已编译的下游产物还会表现为运行期NoSuchMethodError。后续其他使用方可能重复踩到。补充一个范围数据供参考:我们对 0.1.15 与 0.1.16 两个正式发布 jar 的
com.openjiuwen.core.*全部 963 个公开类做了构造器签名逐一比对(两种实现独立跑出同一结果),构造器丢失的类只有ToolInterruptEntry一个,同区间 core jar 的类移除数为 0。所以这是个例,不是普遍做法。复现
建议
补一个 2 参构造器委托,与 builder 省略该字段时语义等价:
两行,不改变任何既有行为,0.1.15 的调用方无需改动即可升级。
如果希望从根上避免同类问题再次发生,可以考虑给这类可演进的 DTO 停用
@AllArgsConstructor(或改为@AllArgsConstructor(access = AccessLevel.PRIVATE)),只对外暴露@Builder+@NoArgsConstructor——builder 天然对新增字段免疫,而@AllArgsConstructor会把「加字段」这个通常向后兼容的动作变成签名变更。这一条属于可选的长期改进,不影响本 issue 的处理。环境
agent-core-java0.1.15 → 0.1.16(930分支,a2549228b)agent-solution/common分支,JDK 21,Maven 3.8.7