Skip to content

[Tech Debt][runtime][java][python] Clarify subagent group cleanup and internal fault propagation #1322

Open

Description

@wenjin272

Search before asking

  • I searched in the issues and found no dedicated issue tracking these follow-ups.

Description

Track two lifecycle and error-handling follow-ups raised during the review of #1320, which fixes #1279 for individual deferred and async awaits in ToolCallAction. These follow-ups are outside that PR's scope.

1. Define cleanup semantics after a caught group await failure

Java SubagentFutureGroup.awaitAll() and Python's group await prepare pending phased handles before executing them. If a member's prepare() throws, execution exits before the per-handle execute() cleanup runs. The failing member and other outstanding members can remain in the pending-call registry.

If the exception propagates out of the user Action, the Action already fails. The contract needs clarification when the caller catches the exception and wants to finish the Action normally: who owns cleanup, and what should happen to the failed member and the remaining members?

Discuss and document the intended behavior before choosing an implementation. Calling group.cancel() is not currently a guaranteed cleanup solution: it invokes each member's cancellation sequentially, can stop at the first cancellation error, and cancellation semantics differ across handle types. Merely untracking every member must not be treated as proof that any underlying work has stopped.

Review discussion: #1320 (comment)

2. Preserve direct propagation of internal framework faults

For internal subagents, ordinary child Action failures become failed SubagentResults and resolve their handles. Framework-side faults in bootstrap, waiting, or durable result completion should instead fail the Action/job and allow recovery.

Currently, InternalSubagentFuture can propagate such a fault without clearing its pending registration. When ToolCallAction catches that exception and converts it into a failed tool response, Action finalization subsequently fails on the unresolved handle. The eventual failure is expected, but the original framework fault is obscured by a secondary lifecycle error.

Clarify and enforce which failures must propagate through ToolCallAction, preserving the original cause and recovery semantics. Adding unconditional finally cleanup alone would not address this: it could allow a framework fault to be treated as a handled tool error and let the Action finish normally.

Review discussion: #1320 (comment)

Completion criteria

  • Define and document the group contract for both propagated and caught await failures, including outstanding members and failures during cleanup.
  • Ensure internal framework faults reach the runtime with their original cause, while ordinary child failures remain failed results.
  • Keep Java and Python behavior aligned and add regression coverage at the Action lifecycle / ToolCallAction boundary.

Are you willing to submit a PR?

  • I'm willing to submit a PR!

Activity

  1. added
    tech debt[Issue Type] User-unaware issues, such as code refactor and infrastructure maintenance.
    priority/minorIndicates the PR or issue related to non-urgent bugs, features, and improvements.
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority/minorIndicates the PR or issue related to non-urgent bugs, features, and improvements.tech debt[Issue Type] User-unaware issues, such as code refactor and infrastructure maintenance.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions