Repository navigation
test(ai): run Live API tests on Gemini 3.8 Live - #17044
andrewheard wants to merge 2 commits into
Conversation
Run every LiveSessionTests case against gemini-3.8-live as well as the Gemini 2.5 Live models, ahead of the 2.5 retirement, and fix problems that made the suite hang or leave sessions connected. - Close every session, even when a test fails, with a new withSession helper. Failing tests previously left their sessions connected, and two resumption tests left their first session open on every run. - Close the first session before resuming it. Gemini 3.x Live models reject a resumption handle while its session is still connected. - Add a one-minute time limit to each test, and a timeout while waiting for a function call cancellation, so a hung test fails instead of stalling the job. - Send three seconds of silence after speech. Gemini 3.x Live models need more than one second of silence to detect the end of speech. - Ask the model to count slowly in the interruption test, so that its response is long enough to interrupt. - Wait up to 10 seconds for responses to video input. - Record known issues for Gemini 3.8 Live, which doesn't cancel non-blocking function calls and sometimes miscounts when automatic activity detection is disabled.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
Address review feedback on the Gemini 3.8 Live test changes. - Fail, instead of passing silently, when a resumption test doesn't receive a session handle. This also removes the String?? workaround in realtime_resumeSession. - Limit the cancellation known issue to the missing cancellation, so a cancellation with the wrong IDs or a dropped connection still fails on Gemini 3.8 Live. Move the timed wait into a tryCollectNextToolCallCancellation() helper. - Require a numeric reply in realtime_automaticActivityDetection_disabled before applying the miscount known issue, so an unrelated reply still fails. - Time out each realtime_interruption attempt after 10 seconds, so all three retries fit within the one-minute limit, and fail if the response stream ends without an interruption instead of passing. - Remove the repeated availability comments, a double blank line, and a DocC link that doesn't resolve, and rewrap a comment that was over 100 columns.
Runs
LiveSessionTestsagainstgemini-3.8-livein addition to the Gemini 2.5 Live models, and fixes problems that made the suite hang or skip closing sessions. This is part of evaluating Gemini 3.8 Live support for #17031.Changes
Gemini 3.8 Live coverage
gemini-3.8-liveto the sharedarguments, so every test that uses them also runs on 3.8 on both backends. (realtime_voiceActivitywas already 3.8-only.)realtime_functionCalling_cancellationnow runs on 3.8 on Agent Platform too. Agent Platform is still skipped for 2.5 because of the existing b/450982184 TODO about function IDs.Closing sessions
LiveGenerativeModel.withSession(sessionResumption:_:)test helper. It connects a session, runs the closure, and closes the session whether the closure returns or throws, including when a#requirefails. Every test now uses it.close()skipped it.realtime_interruptionnever calledclose(), and its retry loop could open up to three sessions per test case.realtime_manual_sessionResumptionandrealtime_sessionResumption_disabledreplaced their first session without closing it. Combined with thedeinitissue under Follow-ups, these likely left sessions connected.realtime_manual_sessionResumptionnow closes the first session before resuming it. Gemini 3.8 Live rejects a resumption handle while its session is still connected ("BidiGenerateContent session is already connected to an existing client").realtime_sessionResumption_disablednow waits for a session handle before closing its first session. Otherwise the message might never be sent, and the test would pass without checking anything.Timeouts
.timeLimit(.minutes(1)). Before, a hung test could stall the job until GitHub Actions' 6-hour job timeout: the job sets notimeout-minutes, and Xcode test timeouts aren't enabled.timeLimit(_:)requires iOS 16, theIntegrationTests-SPMtarget's deployment target is iOS 15, and Swift Testing doesn't allow@availableon a suite.realtime_interruptionattempt now times out after 10 seconds, so all three retries fit in the time limit. The test also now fails if the response stream ends without an interruption; before, it passed.sendVideoRealtime_receiveAudioOutputTranscriptsnow waits up to 10 seconds for a response instead of 5. In my local runs, every failure of this test was a reply that took longer than 5 seconds.Gemini 3.8 behavior
endOfSpeechSilence(3 seconds of silence), which replaces the old padding in the audio, video and interruption tests. Gemini 3.8 Live needs more than one second of silence to detect that the user has stopped speaking. Without it, the 3.8 audio and video tests timed out every time, andrealtime_interruptionhung on Agent Platform.realtime_interruptionnow asks the model to count slowly. With the longer silence, Gemini 2.5 finished its one-word reply before the interrupting audio arrived, so the test failed every time.Known issues
Recorded with
withKnownIssue, only for Gemini 3.8 Live and only around the assertions that fail:realtime_functionCalling_cancellation: Gemini 3.8 Live calls functions withNON_BLOCKINGbehavior by default and only cancelsBLOCKINGcalls automatically (AI Studio migration guide, Agent Platform guide). The SDK can't setFunctionDeclaration.behavioryet. Only the missing cancellation is a known issue: a cancellation with the wrong IDs still fails. It isn't marked intermittent, so Swift Testing will flag it if 3.8 starts sending cancellations.realtime_automaticActivityDetection_disabled: Gemini 3.8 Live sometimes counts 3 or 4 "Hello"s instead of 2. This one is marked intermittent. The test still fails if the model doesn't reply, or replies with something other than a number.Testing
I ran
LiveSessionTestslocally against both backends, on an iPhone 18 Pro simulator (iOS 27.2) with Xcode 27.3. CI uses Xcode 26.2; the Swift Testing APIs used here are available in Swift 6.0. Latest full run:sendAudioRealtime_…,sendVideoRealtime_…,realtime_functionCalling,realtime_sessionResumption_disabled,realtime_interruption,incremental_works,realtime_speechConfig,realtime_voiceActivityrealtime_functionCalling_cancellation,realtime_automaticActivityDetection_disabledrealtime_manual_sessionResumptionandrealtime_resumeSession(Google AI 3.8: no reply after resuming);realtime_automaticActivityDetection_enabled(Agent Platform 2.5: counted 3, expected 1)Remaining flakiness:
realtime_resumeSessionfailed this way on Google AI 3.8 three times and on Google AI 2.5 once, andrealtime_manual_sessionResumptionfailed once on Google AI 3.8. A separate run of 12 iterations per test had one failure in each, on Google AI 3.8 and Agent Platform 2.5. Raising the wait from 5 to 10 seconds didn't help: passing cases reply within a few seconds, and failing cases don't reply at all, so I left the default timeout. Neither failure appears in the two CI logs I checked (the November 9 nightly onmainand fix(ai): replace Mutex to fix crash on iOS < 18 #17024), but CI's retries may hide it.realtime_automaticActivityDetection_enabledmiscounts on both models: Agent Platform 2.5 miscounted in three of my four full runs, and Google AI 3.8 in one. The "count the hellos" prompts look unreliable in general, so I didn't add a 3.8-only known issue. Rewriting the two counting tests would be a separate change.Follow-ups
LiveSessionreleased without callingclose()probably keeps its WebSocket open.LiveSession.close()is documented as running automatically on deinit, butLiveSessionService'sresponsesTaskandmessageQueueTask, and the receive loop inAsyncWebSocket, hold strong references until they're cancelled. That likely stopsdeinitfrom ever running. I'll fix that in a separate PR, with a unit test and a CHANGELOG entry.argumentsonce they're retired.#no-changelog