Skip to content

[FEATURE] Port ReflectAndRetryToolPlugin from adk-python #1390

Description

@svetanis

Please make sure you read the contribution guide and file the issues in the right place.
Contribution guide.

🔴 Required Information

Is your feature request related to a specific problem?

When a tool fails, adk-java gives the model no way to learn what went wrong and try again. A tool
that reports its failure ends the invocation on the first attempt, even when the failure is one the
model could have corrected — malformed arguments, the wrong tool for the job, a precondition it
could have satisfied first.

adk-python ships a plugin for exactly this — ReflectAndRetryToolPlugin. adk-java
has no equivalent.

Describe the Solution You'd Like

ReflectAndRetryToolPlugin in com.google.adk.plugins.reflectandretry, registered on a Runner
like any other plugin, behaving as adk-python's does:

  • intercept tool failures through the two hooks that already exist on Plugin
    onToolErrorCallback for a tool that signals an error, and afterToolCallback for a result that
    carries one;
  • track consecutive failures per tool within a scope, so a success with one tool resets that
    tool's counter without forgiving another's;
  • substitute a structured reflection response — error type, error details, retry count, and guidance
    telling the model to analyze the arguments and not repeat the identical call — for each failure up
    to maxRetries;
  • past the limit, either propagate the original error or return a final "stop using this tool"
    message, per a constructor flag;
  • scope the counters per invocation (default) or globally, via a TrackingScope enum.

No existing class changes and no existing API changes: registration uses the plugin surfaces already
present.

Impact on your work

Applications wanting adk-python's behavior have to reimplement it in application code, where it
drifts from upstream. Not blocking and there is no timeline — this is a parity gap, not an outage.

Willingness to contribute

Yes. A PR follows immediately after this issue: one new public plugin class plus four small
supporting types in a plugins.reflectandretry subpackage, with tests. No existing file is
modified.


🟡 Recommended Information

Describe Alternatives You've Considered

Retry inside the tool itself. This is the obvious workaround and it is not the same thing. A
loop inside the tool repeats the identical call; the point of reflection is to hand the model the
error and its own arguments so it can call differently. A tool cannot fix arguments it did not
choose.

Implement the plugin in application code. It works — the behavior above was verified using
public API only. But it is per-application boilerplate for something the plugin surface exists to
ship once, and every copy drifts from upstream separately.

Widen onToolErrorCallback semantics instead. That would change existing behavior for every
plugin. A new opt-in plugin changes nothing for anyone who does not register it.

Proposed API / Implementation

Registration needs no new API:

Runner runner =
    new InMemoryRunner(agent, "my-app", ImmutableList.of(new ReflectAndRetryToolPlugin(3)));

Both hooks are already declared on Plugin, and both already return the type the plugin needs —
Maybe<Map<String, Object>>, matching Python's Optional[dict[str, Any]]:

// Plugin.java:188
default Maybe<Map<String, Object>> afterToolCallback(
    BaseTool tool, Map<String, Object> toolArgs, ToolContext toolContext, Map<String, Object> result)

// Plugin.java:206
default Maybe<Map<String, Object>> onToolErrorCallback(
    BaseTool tool, Map<String, Object> toolArgs, ToolContext toolContext, Throwable error)

The class is written and tested; the PR carries it.

Additional Context

Observed on 1.7.1-SNAPSHOT, Windows 11 (not OS-specific).

Activity

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

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions