mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 01:29:56 +00:00
refactor(reply): share fast-mode session persistence (#147847)
This commit is contained in:
parent
ba92d2420b
commit
9d5d33201a
2 changed files with 103 additions and 20 deletions
|
|
@ -1,11 +1,14 @@
|
|||
// Tests session usage command output and token accounting summaries.
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { loadSessionEntry, replaceSessionEntry } from "../../config/sessions/session-accessor.js";
|
||||
import type {
|
||||
CostUsageSummary,
|
||||
CostUsageTotals,
|
||||
SessionCostSummary,
|
||||
} from "../../infra/session-cost-usage.js";
|
||||
import { withTempDir } from "../../test-utils/temp-dir.js";
|
||||
import { handleFastCommand, handleUsageCommand } from "./commands-session.js";
|
||||
import type { HandleCommandsParams } from "./commands-types.js";
|
||||
|
||||
|
|
@ -436,6 +439,95 @@ describe("handleFastCommand", () => {
|
|||
expect(sessionEntry?.fastMode).toBe(true);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ mode: "on", value: true, text: "⚙️ Fast mode enabled." },
|
||||
{ mode: "off", value: false, text: "⚙️ Fast mode disabled." },
|
||||
{ mode: "auto", value: "auto", text: "⚙️ Fast mode set to auto." },
|
||||
] as const)("persists /fast $mode on the canonical target", async ({ mode, value, text }) => {
|
||||
await withTempDir("openclaw-fast-command-", async (dir) => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = `/fast ${mode}`;
|
||||
params.storePath = path.join(dir, "sessions.json");
|
||||
params.sessionEntry = { sessionId: "wrapper-session", updatedAt: 1, fastMode: false };
|
||||
const target: NonNullable<HandleCommandsParams["sessionEntry"]> = {
|
||||
sessionId: "target-session",
|
||||
updatedAt: 1,
|
||||
fastMode: mode !== "on",
|
||||
};
|
||||
params.initialSessionEntry = { ...target };
|
||||
params.sessionStore = { [params.sessionKey]: target };
|
||||
await replaceSessionEntry(
|
||||
{ storePath: params.storePath, sessionKey: params.sessionKey },
|
||||
{ ...target },
|
||||
);
|
||||
|
||||
const result = await handleFastCommand(params, true);
|
||||
|
||||
expect(result).toEqual({ shouldContinue: false, reply: { text } });
|
||||
expect(
|
||||
loadSessionEntry({ storePath: params.storePath, sessionKey: params.sessionKey })?.fastMode,
|
||||
).toBe(value);
|
||||
expect(params.sessionStore[params.sessionKey]?.fastMode).toBe(value);
|
||||
expect(params.sessionEntry.fastMode).toBe(false);
|
||||
expect(resolveFastModeStateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
["on", "⚙️ Fast mode enabled."],
|
||||
["off", "⚙️ Fast mode disabled."],
|
||||
["auto", "⚙️ Fast mode set to auto."],
|
||||
["default", "⚙️ Fast mode reset to default."],
|
||||
])("keeps the /fast %s reply without a target entry", async (mode, text) => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = `/fast ${mode}`;
|
||||
params.sessionEntry = undefined;
|
||||
|
||||
expect(await handleFastCommand(params, true)).toEqual({
|
||||
shouldContinue: false,
|
||||
reply: { text },
|
||||
});
|
||||
expect(params.sessionStore).toBeUndefined();
|
||||
expect(resolveFastModeStateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects an invalid /fast mode without mutating the target", async () => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = "/fast invalid";
|
||||
const target = { sessionId: "target-session", updatedAt: 1, fastMode: true };
|
||||
params.sessionEntry = target;
|
||||
params.sessionStore = { [params.sessionKey]: target };
|
||||
|
||||
expect(await handleFastCommand(params, true)).toEqual({
|
||||
shouldContinue: false,
|
||||
reply: { text: "⚙️ Usage: /fast status|auto|on|off|default" },
|
||||
});
|
||||
expect(target).toEqual({ sessionId: "target-session", updatedAt: 1, fastMode: true });
|
||||
expect(resolveFastModeStateMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each(["default", "off"])("reports a /fast %s persistence conflict", async (mode) => {
|
||||
await withTempDir("openclaw-fast-conflict-", async (dir) => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = `/fast ${mode}`;
|
||||
params.storePath = path.join(dir, "sessions.json");
|
||||
const target = { sessionId: "missing-session", updatedAt: 1, fastMode: true };
|
||||
params.sessionEntry = target;
|
||||
params.initialSessionEntry = { ...target };
|
||||
params.sessionStore = { [params.sessionKey]: target };
|
||||
|
||||
expect(await handleFastCommand(params, true)).toEqual({
|
||||
shouldContinue: false,
|
||||
reply: {
|
||||
text: "⚠️ Session changed before this setting could be saved. Retry the command.",
|
||||
},
|
||||
});
|
||||
expect(
|
||||
loadSessionEntry({ storePath: params.storePath, sessionKey: params.sessionKey }),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("clears fast mode for /fast default", async () => {
|
||||
const params = buildUsageParams();
|
||||
params.command.commandBodyNormalized = "/fast default";
|
||||
|
|
|
|||
|
|
@ -325,27 +325,16 @@ export const handleFastCommand: CommandHandler = defineAuthorizedTextCommand(
|
|||
const targetSessionEntry = params.sessionStore?.[params.sessionKey] ?? params.sessionEntry;
|
||||
const resetsToDefault = isSessionDefaultDirectiveValue(rawMode);
|
||||
const nextMode = resetsToDefault ? undefined : normalizeFastMode(rawMode);
|
||||
if (nextMode === undefined) {
|
||||
if (resetsToDefault) {
|
||||
if (targetSessionEntry && params.sessionStore && params.sessionKey) {
|
||||
delete targetSessionEntry.fastMode;
|
||||
if (
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
sessionEntry: targetSessionEntry,
|
||||
touchedFields: ["fastMode"],
|
||||
}))
|
||||
) {
|
||||
return sessionEntryPersistenceConflictReply();
|
||||
}
|
||||
}
|
||||
return sessionCommandReply("⚙️ Fast mode reset to default.");
|
||||
}
|
||||
if (nextMode === undefined && !resetsToDefault) {
|
||||
return sessionCommandReply("⚙️ Usage: /fast status|auto|on|off|default");
|
||||
}
|
||||
|
||||
if (targetSessionEntry && params.sessionStore && params.sessionKey) {
|
||||
targetSessionEntry.fastMode = nextMode;
|
||||
if (resetsToDefault) {
|
||||
delete targetSessionEntry.fastMode;
|
||||
} else {
|
||||
targetSessionEntry.fastMode = nextMode;
|
||||
}
|
||||
if (
|
||||
!(await persistCommandSession({
|
||||
...params,
|
||||
|
|
@ -358,9 +347,11 @@ export const handleFastCommand: CommandHandler = defineAuthorizedTextCommand(
|
|||
}
|
||||
|
||||
return sessionCommandReply(
|
||||
nextMode === "auto"
|
||||
? "⚙️ Fast mode set to auto."
|
||||
: `⚙️ Fast mode ${nextMode ? "enabled" : "disabled"}.`,
|
||||
resetsToDefault
|
||||
? "⚙️ Fast mode reset to default."
|
||||
: nextMode === "auto"
|
||||
? "⚙️ Fast mode set to auto."
|
||||
: `⚙️ Fast mode ${nextMode ? "enabled" : "disabled"}.`,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue