[API][Tool] Align Java and Python Tool outcome contracts - #1074
[API][Tool] Align Java and Python Tool outcome contracts#1074joeyutong wants to merge 5 commits into
Conversation
82adfd8 to
a186ab5
Compare
wenjin272
left a comment
There was a problem hiding this comment.
Thanks for working on aligning the Java and Python tool outcome contracts!
| return asyncio.run( | ||
| self.mcp_server.call_tool_async(self.metadata.name, *args, **kwargs) | ||
| ) | ||
| except Exception as e: |
There was a problem hiding this comment.
Could we also normalize explicit outcomes in PythonMCPTool.call()? That Java wrapper still wraps every normal Python return in ToolResponse.success(...). Returning ToolResponse.error(...) here therefore causes Java agents using Python MCP tools to record failures as successes. This reproduces with real Pemja for both transport exceptions and MCP protocol errors. Please cover this path with a cross-language regression test.
There was a problem hiding this comment.
Fixed. PythonMCPTool now uses the same bridge encoder/decoder as FunctionTool, so an explicit Python ToolResponse.error(...) remains a failed Java ToolResponse. I also added a unit regression and extended MCPCrossLanguageTest with a real FastMCP protocol error over Pemja.
|
|
||
| content = [extract_mcp_content_item(item) for item in result.content] | ||
|
|
||
| if result.isError: |
There was a problem hiding this comment.
Could we move the protocol-error check outside async with self._get_session()? With a real ClientSession, raising here gets wrapped in an AnyIO ExceptionGroup. MCPTool.call() then retains only the outer message, “unhandled errors in a TaskGroup”, losing the original MCP error content and recovery hints. A regression test retaining the real session lifecycle would catch this; the current fake session does not.
There was a problem hiding this comment.
Fixed by moving MCP content/error interpretation outside the session context. The regression now uses a real ClientSession lifecycle and verifies that the original protocol error content is retained instead of only the outer ExceptionGroup message.
a186ab5 to
6546715
Compare
Preserve explicit Tool operation failures across native and cross-language execution without changing existing raw Python Tool return behavior. Generated-by: Codex 0.151.0-alpha.7.2 (GPT-5.6 Sol) Co-Authored-By: Claude Code <noreply@anthropic.com> AI-Model: gpt-5.6-sol AI-Contributed/Feature: 274/274 AI-Contributed/UT: 315/315
Use error and is_error consistently with the established Java ToolResponse contract while keeping the bridge wire field named error. Generated-by: Codex 0.151.0-alpha.7.2 (GPT-5.6 Sol) Co-Authored-By: Claude Code <noreply@anthropic.com> AI-Model: gpt-5.6-sol AI-Contributed/Feature: 28/28 AI-Contributed/UT: 24/24
Keep Java ToolResponse success and error states intact across the Java-to-Python bridge, preserve empty error messages, and add symmetric bridge coverage. Generated-by: Codex 0.151.0-alpha.7.2 (GPT-5.6 Sol) Co-Authored-By: Claude Code <noreply@anthropic.com> AI-Model: gpt-5.6-sol AI-Contributed/Feature: 53/53 AI-Contributed/UT: 148/148
Interpret MCP protocol failures after the ClientSession context closes so AnyIO cleanup does not replace the original error with an ExceptionGroup summary. Co-Authored-By: Claude Code <noreply@anthropic.com> AI-Model: gpt-5 AI-Contributed/Feature: 9/9 AI-Contributed/UT: 17/17
Route Python MCP calls through the shared ToolResponse bridge envelope so explicit Python failures remain failed Java ToolResponses. Cover the result conversion with unit and real FastMCP/Pemja tests. Co-Authored-By: Claude Code <noreply@anthropic.com> AI-Model: gpt-5 AI-Contributed/Feature: 111/111 AI-Contributed/UT: 103/103
6546715 to
b26e162
Compare
Linked issue: #956
Purpose of change
Java can distinguish whether a Tool invocation returned from whether the returned
ToolResponserepresents a successful Tool operation. Python previously exposed only raw return values, so every normal return was recorded as a successful Tool operation.This change aligns the Java and Python Tool outcome contracts:
ToolResponse.success(...)andToolResponse.error(...)while preserving raw Python returns as successful results;Outcome<T>focused on whether the durable invocation returned or raised.ToolResponseEvent, Execution Events, and downstream metrics can therefore consume the same normalized Tool outcome in both languages. The existingToolResponseEvent.responseswire representation is unchanged.Tests
mvn -pl api,plan,runtime,integrations/mcp -am -DskipITs testpytestfor the affected Python Tool API, Tool call, MCP, Skill, and Java bridge suites (66 passed)API
Adds the public Python
flink_agents.api.tools.ToolResponsetype. Existing Python Tools that return raw values remain source- and behavior-compatible.Documentation
doc-neededdoc-not-neededdoc-includedWas this patch authored or co-authored using generative AI tooling?
Generated-by: Codex 0.151.0-alpha.7.2 (GPT-5.6 Sol)