Skip to content

fix: handle missing functionResponse.id during SSE streams#86

Draft
MrOrz wants to merge 1 commit into
masterfrom
fix-sse-function-response-missing-id-7885769929636350666
Draft

fix: handle missing functionResponse.id during SSE streams#86
MrOrz wants to merge 1 commit into
masterfrom
fix-sse-function-response-missing-id-7885769929636350666

Conversation

@MrOrz

@MrOrz MrOrz commented Jun 8, 2026

Copy link
Copy Markdown
Member

Under some circumstances (such as when using ADK's AgentTool or SequentialAgent or when sending via a separate SSE request), the functionResponse.id field may be missing during real-time SSE streaming. This causes the applyEventToState logic in src/lib/chatCache.ts to drop the response because it tries to look up toolInvocations using the name as a fallback, which is undefined (since the original call was saved using its unique id).

As a result, the tool response does not render in the UI during streaming. However, upon a page refresh, the full session history is fetched, which correctly includes the id in the functionResponse, making it appear.

This PR fixes the issue by updating applyEventToState. If part.functionResponse.id is missing but part.functionResponse.name is present, it will iterate through toolInvocations to find the most recent matching tool call by its name that hasn't received a resp yet, and use that id as the key. This ensures the real-time SSE updates toolInvocations correctly and the UI drawer immediately shows the results.


PR created automatically by Jules for task 7885769929636350666 started by @MrOrz

Under some circumstances (such as when using ADK's `AgentTool` or `SequentialAgent`), the `functionResponse.id` field may be missing during real-time SSE streaming. This prevents the frontend from correctly associating the response with its corresponding tool invocation, resulting in the response not rendering in the UI until a full history fetch occurs.

This commit updates `applyEventToState` in `chatCache.ts` to fallback to searching the existing `toolInvocations` for the most recent unresponded tool call with the matching `name` when the `id` is missing. This ensures the live SSE updates are immediately correctly rendered.

Co-authored-by: MrOrz <108608+MrOrz@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request primarily focuses on code formatting, import cleanups, and semicolon removals across various frontend and backend files. Additionally, it introduces a fallback mechanism in src/lib/chatCache.ts to resolve missing functionResponse.ids during SSE by matching the name of the last unanswered tool invocation. Feedback on this change suggests capturing part.functionResponse.name in a local constant to avoid using the non-null assertion operator !, which is safer and more idiomatic in TypeScript.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/lib/chatCache.ts
Comment on lines +242 to +252
if (!key && part.functionResponse.name) {
const matchingIds = Object.keys(toolInvocations).filter(
(id) =>
toolInvocations[id].name === part.functionResponse!.name &&
!toolInvocations[id].resp,
)
if (matchingIds.length > 0) {
// Pick the last one (most recent)
key = matchingIds[matchingIds.length - 1]
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of using the non-null assertion operator ! inside the .filter() callback, capture part.functionResponse.name in a local constant before the filter. This is safer and more idiomatic in TypeScript, as it avoids potential issues with lexical scope narrowing.

      if (!key && part.functionResponse.name) {
        const name = part.functionResponse.name
        const matchingIds = Object.keys(toolInvocations).filter(
          (id) =>
            toolInvocations[id].name === name &&
            !toolInvocations[id].resp,
        )
        if (matchingIds.length > 0) {
          // Pick the last one (most recent)
          key = matchingIds[matchingIds.length - 1]
        }
      }

Base automatically changed from cache-fix to master June 9, 2026 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant