fix(ui): stop stale talk sessions

This commit is contained in:
Vincent Koc
2026-05-04 00:54:51 -07:00
parent b31c001a2b
commit e5f5989aa9
3 changed files with 12 additions and 2 deletions

View File

@@ -61,6 +61,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Control UI/Talk: make failed Talk startup errors dismissable and clear the stale Talk error state when dismissed, so missing realtime voice provider configuration does not leave a permanent chat banner. Fixes #77071. Thanks @ijoshdavis.
- Control UI/Talk: stop and clear failed realtime Talk sessions when dismissing runtime error banners, so the next Talk click starts a fresh session instead of only stopping the stale one. Thanks @vincentkoc.
- Google Chat: create an isolated Google auth transport per auth client, so google-auth-library interceptor mutations do not accumulate across webhook verification and access-token clients. Thanks @vincentkoc.
- Control UI/performance: cap long-task and long-animation-frame diagnostics in the shared event log, so slow-render telemetry does not evict gateway/plugin events from the Debug and Overview views. Thanks @vincentkoc.
- Web fetch: late-bind `web_fetch` config and provider fallback metadata from the active runtime snapshot, matching `web_search` so long-lived tools do not use stale fetch provider settings. Thanks @vincentkoc.

View File

@@ -911,19 +911,23 @@ describe("switchChatSession", () => {
describe("dismissChatError", () => {
it("clears persistent Talk error state", () => {
const stop = vi.fn();
const state = {
lastError: 'Realtime voice provider "openai" is not configured',
lastErrorCode: "UNAVAILABLE",
realtimeTalkActive: false,
realtimeTalkActive: true,
realtimeTalkSession: { stop },
realtimeTalkStatus: "error",
realtimeTalkDetail: 'Realtime voice provider "openai" is not configured',
realtimeTalkTranscript: "partial transcript",
} as AppViewState;
} as unknown as AppViewState & { realtimeTalkSession: { stop(): void } | null };
dismissChatError(state);
expect(state.lastError).toBeNull();
expect(state.lastErrorCode).toBeNull();
expect(stop).toHaveBeenCalledOnce();
expect(state.realtimeTalkSession).toBeNull();
expect(state.realtimeTalkActive).toBe(false);
expect(state.realtimeTalkStatus).toBe("idle");
expect(state.realtimeTalkDetail).toBeNull();

View File

@@ -623,6 +623,11 @@ export function dismissChatError(state: AppViewState) {
state.lastError = null;
state.lastErrorCode = null;
if (state.realtimeTalkStatus === "error") {
const talkHost = state as unknown as {
realtimeTalkSession?: { stop(): void } | null;
};
talkHost.realtimeTalkSession?.stop();
talkHost.realtimeTalkSession = null;
state.realtimeTalkActive = false;
state.realtimeTalkStatus = "idle";
state.realtimeTalkDetail = null;