Zhuoxi2000 opened a new issue, #947: URL: https://github.com/apache/flink-agents/issues/947
### Search before asking - [x] I searched in the [issues](https://github.com/apache/flink-agents/issues) and found nothing similar. ### Description The Gemini Developer API frequently returns `functionCall` parts without an `id`. In `GeminiChatModelConnection.convertFunctionCall`, the id is read via `functionCall.id().orElse(null)`, and when absent, neither `id` nor `original_id` is put into the tool-call map. Two things break downstream: 1. `ToolCallAction` reads the id via `String.valueOf(toolCall.get("id"))`, producing the literal string `"null"`. With two or more parallel id-less calls, all results collide under the `"null"` key in the `success` / `responses` / `error` maps, so only the last one survives. 2. `original_id` is what `ToolCallAction` propagates as the TOOL message's `externalId`, which is how the follow-up turn recovers the function name for Gemini's `functionResponse` part (`buildToolCallIdToNameMap` + `resolveToolFunctionName`). Without it, the second request throws `IllegalArgumentException("Tool message must carry the function name...")`. **Expected**: a documented, supported flow — Gemini setup with tools — completes the tool round trip. **Actual**: turn 1 executes the tool, turn 2 crashes. The class javadoc assumes a native id is always present ("Tool calls are returned as functionCall parts carrying a native id"), but the Developer API does not guarantee one. Existing unit tests always build `FunctionCall.builder().id("call_1")...`, so the id-less path is never exercised end-to-end (the one id-less case, `testConvertFunctionCallNoSignature`, only asserts `thought_signature` absence). Proposed fix: synthesize a UUID when the native id is absent and set both `id` and `original_id`, marked (e.g. `synthetic_id`) so `convertToolCallToPart` never echoes a fabricated id back to the Gemini API — on-the-wire behavior for id-less calls stays unchanged, while the runtime round trip works. ### How to reproduce Unit-level (no network): 1. `Map<String, Object> call = connection.convertFunctionCall(FunctionCall.builder().name("get_weather").args(Map.of()).build(), null);` → the map contains neither `id` nor `original_id`. 2. Feed that tool call through the runtime shape: the TOOL `ChatMessage` never gets an `externalId`, so `convertToContent(toolMessage, buildToolCallIdToNameMap(messages))` throws `IllegalArgumentException("Tool message must carry the function name...")`. End-to-end: a Java agent with a `GeminiChatModelSetup` and `tools: [...]` against the Gemini Developer API. First model turn calls the tool successfully; the follow-up chat request throws the exception above. With two tools called in parallel, additionally observe that both results key on `"null"` and one overwrites the other. ### Version and environment Current main (4d99567, 2026-07-25). Java 17, google-genai SDK as pinned by the repo. Affects the Gemini Developer API path (`api_key` mode); verified with unit tests against the SDK types, no network required. ### Are you willing to submit a PR? - [x] I'm willing to submit a PR! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
