fix(subagent): dynamic subagent FAILED/CANCELLED payloads#2187
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
oss-maintainer
left a comment
There was a problem hiding this comment.
Summary
Introduces TaskCompletionEvent record to replace bare-parameter callback, adding status and errorMessage fields so consumers can distinguish COMPLETED/FAILED/CANCELLED without re-reading TaskRecord.
Findings
- [Info] TaskCompletionEvent record encapsulates all terminal state. Clean API design.
- [Info] WorkspaceTaskRepository gains localTaskStatuses map for terminal state tracking. Good.
- [Info] Heartbeat tasks skip terminal-state tasks. Correct optimization.
- [Info] Orphan sweep marks timed-out RUNNING tasks as FAILED. Good cleanup.
- [Info] 508-line test file covers all scenarios. Excellent coverage.
Verdict
Well-structured fix with thorough tests. LGTM.
Automated review by github-manager
AgentScopeJavaBot
left a comment
There was a problem hiding this comment.
🤖 AI Review
Solid refactoring that addresses issue #2159 by introducing an immutable TaskCompletionEvent record to replace bare callback parameters. The design correctly separates COMPLETED/FAILED/CANCELLED terminal states, allowing HarnessAgent and SubagentsMiddleware to construct distinct notification messages without re-reading TaskRecord.
The WorkspaceTaskRepository enhancements (terminal state tracking, heartbeat skip for terminated tasks, orphan sweep marking FAILED) are well-implemented. Test coverage spans all three terminal states with both callback-level and middleware-level tests.
Minor nits: (1) TaskCompletionEvent.status should have a @NonNull semantic constraint or Objects.requireNonNull guard. (2) terminatedTaskIds set grows unboundedly — consider a bounded cache for long-running services. (3) SWEEP_MARKER_PATH writes empty files that provide no info during ops troubleshooting — consider writing {"ts": ...} JSON. (4) The orphan scanner callback trigger path lacks dedicated unit test coverage.
| * @param taskId task identifier | ||
| * @param subAgentId which subagent type executed this task | ||
| * @param sessionId parent session scope | ||
| * @param status terminal status — one of COMPLETED / FAILED / CANCELLED |
There was a problem hiding this comment.
[minor] The status field should carry a non-null semantic constraint. Consider adding Objects.requireNonNull(status) in a compact constructor, or documenting @code non-null in the Javadoc, since null status would break downstream switch(event.status()) logic.
AgentScopeJavaBot
left a comment
There was a problem hiding this comment.
🤖 AI Review
Solid refactoring that addresses issue #2159 by introducing an immutable TaskCompletionEvent record to replace bare callback parameters. The design correctly separates COMPLETED/FAILED/CANCELLED terminal states, allowing HarnessAgent and SubagentsMiddleware to construct distinct notification messages without re-reading TaskRecord.
The WorkspaceTaskRepository enhancements (terminal state tracking, heartbeat skip for terminated tasks, orphan sweep marking FAILED) are well-implemented. Test coverage spans all three terminal states with both callback-level and middleware-level tests.
Minor nits: (1) TaskCompletionEvent.status should have a @NonNull semantic constraint or Objects.requireNonNull guard. (2) terminatedTaskIds set grows unboundedly — consider a bounded cache for long-running services. (3) SWEEP_MARKER_PATH writes empty files that provide no info during ops troubleshooting — consider writing {"ts": ...} JSON. (4) The orphan scanner callback trigger path lacks dedicated unit test coverage.
| * @param taskId task identifier | ||
| * @param subAgentId which subagent type executed this task | ||
| * @param sessionId parent session scope | ||
| * @param status terminal status — one of COMPLETED / FAILED / CANCELLED |
There was a problem hiding this comment.
[minor] The status field should carry a non-null semantic constraint. Consider adding Objects.requireNonNull(status) in a compact constructor, or documenting @code non-null in the Javadoc, since null status would break downstream switch(event.status()) logic.
关联 issue
AgentScope-Java Version
2.0.1-SNAPSHOT
Description
Background
TaskCompletionCallback原本是一个包含多个裸参数(rc, taskId, subAgentId, sessionId, result)的函数式接口,无法携带任务的终态状态(COMPLETED / FAILED / CANCELLED)和失败原因,消费者需要重新读取持久化的TaskRecord才能区分任务的最终状态。此外,WorkspaceTaskRepository缺少对终态状态的本地追踪和孤儿任务清理机制。Root Cause
回调签名中缺少
TaskStatus和errorMessage字段,导致HarnessAgent和SubagentsMiddleware在收到回调时无法可靠地区分任务是正常完成、失败还是被取消,只能依赖result是否为 null 进行粗略判断。Fix
引入不可变的
TaskCompletionEventrecord 替代原有的裸参数回调签名,新增status和errorMessage字段,使消费者无需重新读取TaskRecord即可获取任务的权威终态信息。同步更新WorkspaceTaskRepository增加终态状态的本地追踪、心跳过终态任务、以及孤儿扫描中标记过期运行任务为 FAILED 的能力。Changed files:
1.
TaskCompletionEvent.java(新增)新增不可变 record,封装
rc, taskId, subAgentId, sessionId, status, result, errorMessage,替代原来TaskCompletionCallback的裸参数列表。2.
SubagentsMiddleware.java将回调签名从
(rc, taskId, subAgentId, sessionId, result)更新为(event) -> { ... },通过event.status()区分终态类型,构造不同的HintItem内容。3.
HarnessAgent.java将
setCompletionCallback的回调从裸参数改为接收TaskCompletionEvent,使用switch (event.status())为 COMPLETED / FAILED / CANCELLED 三种终态分别构造不同的通知消息格式。4.
WorkspaceTaskRepository.javaTaskCompletionCallback接口签名更新为接收TaskCompletionEvent;localTaskStatusesmap 追踪本地任务的终态状态;TaskCompletionEvent。5.
WorkspaceTaskRepositoryTest.java(新增,约 508 行)覆盖
putTask、getTask、listTasks、cancelTask、heartbeat、sweepOrphanedTasks等场景的单元测试,包括会话隔离、终态不被覆盖、跨节点过滤、孤儿标记等边界条件。Checklist
mvn spotless:applymvn test)