mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix(ui): keep live chat for canonical session events
This commit is contained in:
@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Control UI/chat: keep live replies visible when a raw session alias such as `main` sends the chat turn but Gateway emits events under the canonical session key for the same run. Fixes #73716. Thanks @teebes.
|
||||
- TTS/Telegram: keep trusted local audio generated by the TTS tool queued for voice-note delivery even when the run-level built-in tool list omits the raw `tts` name. Fixes #74752. Thanks @Loveworld3033 and @andyliu.
|
||||
- TTS: require explicit user or config audio intent for the agent speech tool so dashboard chats stay text unless audio is requested. Fixes #69777. Thanks @alexandre-leng.
|
||||
- Plugins/config: keep bundled source-checkout plugins from being runtime-gated by install-only `minHostVersion` metadata, accept prerelease host floors, trim plugin-service startup failures to one log line, and avoid broad channel-runtime loading during base config parsing. Thanks @vincentkoc.
|
||||
|
||||
@@ -77,7 +77,7 @@ describe("handleChatEvent", () => {
|
||||
expect(handleChatEvent(state, undefined)).toBe(null);
|
||||
});
|
||||
|
||||
it("returns null when sessionKey does not match", () => {
|
||||
it("returns null when sessionKey does not match and no active run is in flight", () => {
|
||||
const state = createState({ sessionKey: "main" });
|
||||
const payload: ChatEventPayload = {
|
||||
runId: "run-1",
|
||||
@@ -87,6 +87,73 @@ describe("handleChatEvent", () => {
|
||||
expect(handleChatEvent(state, payload)).toBe(null);
|
||||
});
|
||||
|
||||
it("accepts delta events for the active run when gateway emits a canonical session key", () => {
|
||||
const state = createState({
|
||||
sessionKey: "main",
|
||||
chatRunId: "run-1",
|
||||
chatStream: null,
|
||||
});
|
||||
const payload: ChatEventPayload = {
|
||||
runId: "run-1",
|
||||
sessionKey: "agent:main:main",
|
||||
state: "delta",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Live reply" }],
|
||||
},
|
||||
};
|
||||
|
||||
expect(handleChatEvent(state, payload)).toBe("delta");
|
||||
expect(state.chatStream).toBe("Live reply");
|
||||
expect(state.chatRunId).toBe("run-1");
|
||||
});
|
||||
|
||||
it("accepts final events for the active run when gateway emits a canonical session key", () => {
|
||||
const state = createState({
|
||||
sessionKey: "main",
|
||||
chatRunId: "run-1",
|
||||
chatStream: "Live reply",
|
||||
chatStreamStartedAt: 100,
|
||||
});
|
||||
const payload: ChatEventPayload = {
|
||||
runId: "run-1",
|
||||
sessionKey: "agent:main:main",
|
||||
state: "final",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Live reply" }],
|
||||
},
|
||||
};
|
||||
|
||||
expect(handleChatEvent(state, payload)).toBe("final");
|
||||
expect(state.chatMessages).toEqual([payload.message]);
|
||||
expect(state.chatRunId).toBe(null);
|
||||
expect(state.chatStream).toBe(null);
|
||||
expect(state.chatStreamStartedAt).toBe(null);
|
||||
});
|
||||
|
||||
it("still drops events when neither session key nor active run id matches", () => {
|
||||
const state = createState({
|
||||
sessionKey: "main",
|
||||
chatRunId: "run-1",
|
||||
chatStream: "Working...",
|
||||
});
|
||||
const payload: ChatEventPayload = {
|
||||
runId: "run-2",
|
||||
sessionKey: "agent:main:main",
|
||||
state: "delta",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Wrong run" }],
|
||||
},
|
||||
};
|
||||
|
||||
expect(handleChatEvent(state, payload)).toBe(null);
|
||||
expect(state.chatRunId).toBe("run-1");
|
||||
expect(state.chatStream).toBe("Working...");
|
||||
expect(state.chatMessages).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns null for delta from another run", () => {
|
||||
const state = createState({
|
||||
sessionKey: "main",
|
||||
|
||||
@@ -714,7 +714,12 @@ export function handleChatEvent(state: ChatState, payload?: ChatEventPayload) {
|
||||
if (!payload) {
|
||||
return null;
|
||||
}
|
||||
if (payload.sessionKey !== state.sessionKey) {
|
||||
const sessionMatches = payload.sessionKey === state.sessionKey;
|
||||
const activeRunMatches =
|
||||
state.chatRunId !== null &&
|
||||
typeof payload.runId === "string" &&
|
||||
payload.runId === state.chatRunId;
|
||||
if (!sessionMatches && !activeRunMatches) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user