mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
test(auto-reply): assert bare reset acknowledgement
This commit is contained in:
@@ -15,7 +15,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Gateway/startup: start chat channels without waiting for primary model prewarm, keeping model warmup bounded in the background so Slack and other channels come online promptly when provider discovery is slow. Supersedes #73420. Thanks @dorukardahan.
|
||||
- Gateway/install: carry env-backed config SecretRefs such as `channels.discord.token` into generated service environments when they are present only in the installing shell, while keeping gateway auth SecretRefs non-persisted. Fixes #67817; supersedes #73426. Thanks @wdimaculangan and @ztexydt-cqh.
|
||||
- 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.
|
||||
- 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 and #73412. Thanks @hoyanhan, @wenxu007, and @amdhelper.
|
||||
- Auto-reply: preserve voice-note media from silent turns while continuing to suppress text and non-voice media, so `NO_REPLY` TTS replies still deliver the requested audio bubble. (#73406) Thanks @zqchris.
|
||||
- Channels/Mattermost: stop enqueueing regular inbound posts as system events, so Mattermost user messages reach the model only as user-role inbound-envelope content instead of also appearing as `System: Mattermost message...` directives. Fixes #71795. Thanks @juan-flores077.
|
||||
- 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.
|
||||
|
||||
@@ -125,8 +125,9 @@ knob.
|
||||
`agents.defaults.bootstrapTotalMaxChars`:
|
||||
normal workspace bootstrap injection.
|
||||
- `agents.defaults.startupContext.*`:
|
||||
one-shot `/new` and `/reset` startup prelude, including recent daily
|
||||
`memory/*.md` files.
|
||||
one-shot reset/startup model-run prelude, including recent daily
|
||||
`memory/*.md` files. Bare chat `/new` and `/reset` commands are
|
||||
acknowledged without invoking the model.
|
||||
- `skills.limits.*`:
|
||||
the compact skills list injected into the system prompt.
|
||||
- `agents.defaults.contextLimits.*`:
|
||||
@@ -142,8 +143,9 @@ budget:
|
||||
|
||||
#### `agents.defaults.startupContext`
|
||||
|
||||
Controls the first-turn startup prelude injected on bare `/new` and `/reset`
|
||||
runs.
|
||||
Controls the first-turn startup prelude injected on reset/startup model runs.
|
||||
Bare chat `/new` and `/reset` commands acknowledge the reset without invoking
|
||||
the model, so they do not load this prelude.
|
||||
|
||||
```json5
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ OpenClaw assembles its own system prompt on every run. It includes:
|
||||
with optional per-agent override at
|
||||
`agents.list[].skillsLimits.maxSkillsPromptChars`.
|
||||
- Self-update instructions
|
||||
- Workspace + bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md` when new, plus `MEMORY.md` when present). Lowercase root `memory.md` is not injected; it is legacy repair input for `openclaw doctor --fix` when paired with `MEMORY.md`. Large files are truncated by `agents.defaults.bootstrapMaxChars` (default: 12000), and total bootstrap injection is capped by `agents.defaults.bootstrapTotalMaxChars` (default: 60000). `memory/*.md` daily files are not part of the normal bootstrap prompt; they remain on-demand via memory tools on ordinary turns, but bare `/new` and `/reset` can prepend a one-shot startup-context block with recent daily memory for that first turn. That startup prelude is controlled by `agents.defaults.startupContext`.
|
||||
- Workspace + bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md` when new, plus `MEMORY.md` when present). Lowercase root `memory.md` is not injected; it is legacy repair input for `openclaw doctor --fix` when paired with `MEMORY.md`. Large files are truncated by `agents.defaults.bootstrapMaxChars` (default: 12000), and total bootstrap injection is capped by `agents.defaults.bootstrapTotalMaxChars` (default: 60000). `memory/*.md` daily files are not part of the normal bootstrap prompt; they remain on-demand via memory tools on ordinary turns, but reset/startup model runs can prepend a one-shot startup-context block with recent daily memory for that first turn. Bare chat `/new` and `/reset` commands are acknowledged without invoking the model. The startup prelude is controlled by `agents.defaults.startupContext`.
|
||||
- Time (UTC + user timezone)
|
||||
- Reply tags + heartbeat behavior
|
||||
- Runtime metadata (host/OS/model/thinking)
|
||||
|
||||
@@ -159,7 +159,7 @@ Example:
|
||||
|
||||
- Session files: `~/.openclaw/agents/<agentId>/sessions/{{SessionId}}.jsonl`
|
||||
- Session metadata (token usage, last route, etc): `~/.openclaw/agents/<agentId>/sessions/sessions.json` (legacy: `~/.openclaw/sessions/sessions.json`)
|
||||
- `/new` or `/reset` starts a fresh session for that chat (configurable via `resetTriggers`). If sent alone, the agent replies with a short hello to confirm the reset.
|
||||
- `/new` or `/reset` starts a fresh session for that chat (configurable via `resetTriggers`). If sent alone, OpenClaw acknowledges the reset without invoking the model.
|
||||
- `/compact [instructions]` compacts the session context and reports the remaining context budget.
|
||||
|
||||
## Heartbeats (proactive mode)
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
makeCfg,
|
||||
mockRunEmbeddedPiAgentOk,
|
||||
requireSessionStorePath,
|
||||
runGreetingPromptForBareNewOrReset,
|
||||
expectBareNewOrResetAcknowledged,
|
||||
withTempHome,
|
||||
} from "../../test/helpers/auto-reply/trigger-handling-test-harness.js";
|
||||
import { loadSessionStore, resolveSessionKey } from "../config/sessions.js";
|
||||
@@ -375,7 +375,7 @@ describe("trigger handling", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("prepends runtime-loaded daily memory context on bare /new", async () => {
|
||||
it("acknowledges bare /new without invoking the model or loading startup memory", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const workspaceDir = join(home, "openclaw");
|
||||
const nowMs = Date.now();
|
||||
@@ -392,18 +392,12 @@ describe("trigger handling", () => {
|
||||
|
||||
const res = await runAuthorizedSmsCommand("/new", cfg);
|
||||
|
||||
expect(maybeReplyText(res)).toBe("hello");
|
||||
const prompt = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0]?.prompt ?? "";
|
||||
expect(prompt).toContain("[Startup context loaded by runtime]");
|
||||
expect(prompt).toContain(`[Untrusted daily memory: memory/${todayStamp}.md]`);
|
||||
expect(prompt).toContain("BEGIN_QUOTED_NOTES");
|
||||
expect(prompt).toContain("today startup note");
|
||||
expect(prompt).toContain(`[Untrusted daily memory: memory/${yesterdayStamp}.md]`);
|
||||
expect(prompt).toContain("yesterday startup note");
|
||||
expect(maybeReplyText(res)).toBe("✅ New session started.");
|
||||
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("treats normalized /RESET as reset for startupContext.applyOn", async () => {
|
||||
it("acknowledges normalized bare /RESET without invoking the model", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const workspaceDir = join(home, "openclaw");
|
||||
const nowMs = Date.now();
|
||||
@@ -418,10 +412,8 @@ describe("trigger handling", () => {
|
||||
|
||||
const res = await runAuthorizedSmsCommand("/RESET", cfg);
|
||||
|
||||
expect(maybeReplyText(res)).toBe("hello");
|
||||
const prompt = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0]?.prompt ?? "";
|
||||
expect(prompt).toContain(`[Untrusted daily memory: memory/${todayStamp}.md]`);
|
||||
expect(prompt).toContain("reset startup note");
|
||||
expect(maybeReplyText(res)).toBe("✅ Session reset.");
|
||||
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -824,7 +816,7 @@ describe("trigger handling", () => {
|
||||
|
||||
it("handles bare session reset, inline commands, and unauthorized inline status", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
await runGreetingPromptForBareNewOrReset({ home, body: "/new", getReplyFromConfig });
|
||||
await expectBareNewOrResetAcknowledged({ home, body: "/new", getReplyFromConfig });
|
||||
await expectResetBlockedForNonOwner({ home });
|
||||
await expectInlineCommandHandledAndStripped({
|
||||
home,
|
||||
|
||||
@@ -414,7 +414,7 @@ export async function expectInlineCommandHandledAndStripped(params: {
|
||||
expect(text).toBe("ok");
|
||||
}
|
||||
|
||||
export async function runGreetingPromptForBareNewOrReset(params: {
|
||||
export async function expectBareNewOrResetAcknowledged(params: {
|
||||
home: string;
|
||||
body: "/new" | "/reset";
|
||||
getReplyFromConfig: typeof import("../../../src/auto-reply/reply.js").getReplyFromConfig;
|
||||
@@ -440,12 +440,8 @@ export async function runGreetingPromptForBareNewOrReset(params: {
|
||||
makeCfg(params.home),
|
||||
);
|
||||
const text = Array.isArray(res) ? res[0]?.text : res?.text;
|
||||
expect(text).toBe("hello");
|
||||
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
|
||||
const prompt = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0]?.prompt ?? "";
|
||||
expect(prompt).toContain("A new session was started via /new or /reset");
|
||||
expect(prompt).toContain("Execute your Session Startup sequence now");
|
||||
expect(prompt).toContain("read the required files before responding to the user");
|
||||
expect(text).toBe(params.body === "/reset" ? "✅ Session reset." : "✅ New session started.");
|
||||
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
|
||||
}
|
||||
|
||||
export function installTriggerHandlingE2eTestHooks() {
|
||||
|
||||
Reference in New Issue
Block a user