fix(auto-reply): acknowledge bare reset commands

This commit is contained in:
Peter Steinberger
2026-04-28 09:31:04 +01:00
parent 8178b62187
commit a68ca1ae0b
3 changed files with 57 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Auto-reply/commands: stop bare `/reset` and `/new` after reset hooks acknowledge the command, so non-ACP channels no longer fall through into empty provider calls while `/reset <message>` and `/new <message>` still seed the next model turn. Fixes #73367. Thanks @hoyanhan and @wenxu007.
- Agents/Anthropic: send implicit Anthropic beta headers only to direct public Anthropic endpoints, including OAuth, so custom Anthropic-compatible providers no longer mis-handle unsupported beta flags unless explicitly configured. Refs #73346. Thanks @byBrodowski.
- Skills: require explicit `skills.entries.coding-agent.enabled` before exposing the bundled coding-agent skill, so installs with Codex on PATH but no OpenAI auth do not silently offer Codex delegation. Fixes #73358. Thanks @LaFleurAdvertising and @Sanjays2402.
- Plugins/startup: precompute bundled runtime mirror fingerprints before taking the mirror lock, including dist-runtime canonical roots, so Docker Desktop/WSL cold starts no longer hold `.openclaw-runtime-mirror.lock` while scanning slow persisted volumes. Fixes #73339. Thanks @1yihui.

View File

@@ -430,4 +430,52 @@ describe("handleCommands reset hooks", () => {
expect(triggerInternalHookMock).not.toHaveBeenCalled();
expect(resetMocks.resetConfiguredBindingTargetInPlace).not.toHaveBeenCalled();
});
it("acknowledges bare /reset without falling through to model execution", async () => {
const params = buildResetParams("/reset", {
commands: { text: true },
channels: { whatsapp: { allowFrom: ["*"] } },
} as OpenClawConfig);
const result = await maybeHandleResetCommand(params);
expect(result).toEqual({
shouldContinue: false,
reply: { text: "✅ Session reset." },
});
expect(triggerInternalHookMock).toHaveBeenCalledWith(
expect.objectContaining({ type: "command", action: "reset" }),
);
});
it("acknowledges bare /new without falling through to model execution", async () => {
const params = buildResetParams("/new", {
commands: { text: true },
channels: { whatsapp: { allowFrom: ["*"] } },
} as OpenClawConfig);
const result = await maybeHandleResetCommand(params);
expect(result).toEqual({
shouldContinue: false,
reply: { text: "✅ New session started." },
});
expect(triggerInternalHookMock).toHaveBeenCalledWith(
expect.objectContaining({ type: "command", action: "new" }),
);
});
it("keeps reset tails falling through so the model receives the user input", async () => {
const params = buildResetParams("/new take notes", {
commands: { text: true },
channels: { whatsapp: { allowFrom: ["*"] } },
} as OpenClawConfig);
const result = await maybeHandleResetCommand(params);
expect(result).toBeNull();
expect(triggerInternalHookMock).toHaveBeenCalledWith(
expect.objectContaining({ type: "command", action: "new" }),
);
});
});

View File

@@ -166,5 +166,13 @@ export async function maybeHandleResetCommand(
previousSessionEntry: params.previousSessionEntry,
workspaceDir: params.workspaceDir,
});
if (!resetTail) {
return {
shouldContinue: false,
reply: {
text: commandAction === "reset" ? "✅ Session reset." : "✅ New session started.",
},
};
}
return null;
}