fix(webchat): create dashboard sessions from New Chat

This commit is contained in:
clawsweeper
2026-05-01 14:34:27 +00:00
parent 62bd87a65a
commit fa0bfe9d70
3 changed files with 26 additions and 3 deletions

View File

@@ -423,7 +423,7 @@ Docs: https://docs.openclaw.ai
- Outbound/security: strip known internal runtime scaffolding such as `<system-reminder>` and `<previous_response>` at the final channel delivery boundary and keep Discord output on targeted tag stripping, so degraded harness replies cannot leak those tags to users. Fixes #73595. Thanks @gabrielexito-stack and @martingarramon.
- Security/Telegram: load Telegram security adapters in read-only audit/doctor, audit malformed Telegram DM `allowFrom` entries even when groups are disabled, and keep allowlist DM audits from counting stale pairing-store senders, so public/shared-DM risk checks stay accurate. Refs #73698. Thanks @xace1825.
- Plugins: remove hidden manifest, provider-owner, bootstrap, and channel metadata caches so plugin installs, manifest edits, and bundled-root changes are visible on the next metadata read while keeping runtime/module loader caches for actual plugin code. Thanks @shakkernerd.
- Control UI/WebChat: create a fresh dashboard session from the New Chat button instead of resetting the current transcript with `/new`, while keeping explicit `/new` reset behavior, preserving in-progress composer state when creation cannot safely switch sessions, and showing retry feedback while sessions are already refreshing. Carries forward #52042 and #52746. Thanks @bobashopcashier and @vincentkoc.
- Control UI/WebChat: create a fresh dashboard session from the New Chat button instead of resetting the current transcript with `/new`, while keeping explicit `/new` reset behavior, preserving in-progress composer edits during delayed session creation or when creation cannot safely switch sessions, and showing retry feedback while sessions are already refreshing. Carries forward #52042 and #52746. Thanks @bobashopcashier and @vincentkoc.
- CLI/plugins: use plugin metadata snapshots for install slot selection and add opt-in plugin lifecycle timing traces, so plugin install avoids runtime-loading the plugin registry for metadata-only decisions. Thanks @shakkernerd.
- fix(plugins): restrict bundled plugin dir resolution to trusted package roots. (#73275) Thanks @pgondhi987.
- fix(security): prevent workspace PATH injection via service env and trash helpers. (#73264) Thanks @pgondhi987.

View File

@@ -589,6 +589,29 @@ describe("createChatSession", () => {
expect(loadChatHistoryMock).toHaveBeenCalledWith(state);
});
it("preserves draft and attachment edits made while session creation is in flight", async () => {
const state = createChatSessionState();
const updatedAttachments = [
{ id: "att-2", mimeType: "image/png", dataUrl: "data:image/png;base64,BBB" },
];
createSessionAndRefreshMock.mockImplementation(async () => {
state.chatMessage = "updated draft";
state.chatAttachments = updatedAttachments;
return "agent:ops:dashboard:new-chat";
});
refreshChatAvatarMock.mockResolvedValue(undefined);
refreshSlashCommandsMock.mockResolvedValue(undefined);
loadChatHistoryMock.mockResolvedValue(undefined);
loadSessionsMock.mockResolvedValue(undefined);
await createChatSession(state);
expect(state.sessionKey).toBe("agent:ops:dashboard:new-chat");
expect(state.chatMessage).toBe("updated draft");
expect(state.chatAttachments).toBe(updatedAttachments);
expect(loadChatHistoryMock).toHaveBeenCalledWith(state);
});
it("ignores a stale create response after the active session changes", async () => {
const state = createChatSessionState();
createSessionAndRefreshMock.mockImplementation(async () => {

View File

@@ -617,8 +617,6 @@ export async function createChatSession(state: AppViewState) {
state.lastError = null;
const previousSessionKey = state.sessionKey;
const preservedDraft = state.chatMessage;
const preservedAttachments = state.chatAttachments;
const parentSessionKey = state.sessionsResult?.sessions.some(
(row) => row.key === previousSessionKey,
)
@@ -648,6 +646,8 @@ export async function createChatSession(state: AppViewState) {
return;
}
const preservedDraft = state.chatMessage;
const preservedAttachments = state.chatAttachments;
switchChatSession(state, nextSessionKey);
state.chatMessage = preservedDraft;
state.chatAttachments = preservedAttachments;