Skip to content

[Tech Debt][API][Tool] Align Java and Python Tool outcome contracts #956

Description

@joeyutong

Search before asking

  • I searched the issues and found nothing similar.

Description

Background

Java and Python currently expose different Tool result contracts:

  • Java Tool.call returns ToolResponse, which can explicitly represent success or failure without throwing an exception.
  • Python Tool.call returns Any. An exception represents failure, while every normal return is treated as success because Python has no equivalent explicit Tool result type.

PR #926 has introduced parallel Tool calls and the cross-language Outcome abstraction for durable batch execution. The resulting model has two distinct outcome layers:

Outcome<T>   = whether the durable invocation returned or raised
ToolResponse = whether the Tool operation itself succeeded or failed

Java handles both layers for sequential and parallel calls: a successful Outcome<ToolResponse> may still contain an unsuccessful ToolResponse. Python can currently represent only the invocation layer, so every Outcome.success(value) is treated as a successful Tool operation.

This difference is now visible through several framework surfaces:

  • ToolResponseEvent.success and ToolResponseEvent.error;
  • Tool Execution Events and Agent Trace;
  • Tool and MCP operational metrics proposed in PR #955;
  • Java/Python Tool bridges;
  • MCP protocol-level error results.

There are also concrete built-in cases that cannot be represented consistently today. For example, Java and Python load_skill return normal success values when the Skill manager is unavailable, a Skill does not exist, or a requested Skill resource does not exist. These responses contain useful guidance for the model, but Trace and metrics classify them as successful Tool calls.

Proposed direction

Define one Tool outcome contract across Java and Python while preserving compatibility for existing Python Tools:

  • A normal raw Python return remains a successful Tool result.
  • Both languages can explicitly return a successful or failed Tool result; Python exposes ToolResponse.success(...) and ToolResponse.error(...) for this purpose.
  • An invocation exception remains a failed Tool result.
  • Generic durable Outcome keeps its invocation-level meaning and does not absorb Tool-specific semantics.
  • Sequential and parallel Tool-call paths normalize and record results through the same logic.
  • Java/Python bridges preserve explicit Tool success, failure, and error details.
  • ToolResponseEvent, Execution Events, and operational metrics consume the same normalized Tool outcome.
  • load_skill missing-manager, missing-Skill, and missing-resource responses become explicit Tool failures while retaining their current model-facing messages.
  • MCP protocol-level error results map to failed Tool outcomes instead of successful content.

The runtime must not infer failure by inspecting arbitrary Tool payloads such as strings or dictionaries. Aligning the wire representation of all existing ToolResponseEvent.responses payloads is not required for this change; existing event payload compatibility should be preserved.

Expected validation

Cover native Java, native Python, and both cross-language directions for:

  • normal raw success;
  • explicit returned success and failure;
  • thrown exception;
  • sequential and parallel execution;
  • load_skill failure responses;
  • MCP protocol-level failure;
  • consistent ToolResponseEvent and Execution Event outcomes.

Are you willing to submit a PR?

  • I'm willing to submit a PR!

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

fixVersion/0.4.0tech 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