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]

Reply via email to