mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:40:44 +00:00
fix: stop heartbeat prompt leaking into user runs (#69278) (thanks @stainlu)
This commit is contained in:
@@ -60,6 +60,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/restart continuation: durably hand restart continuations to a session-delivery queue before deleting the restart sentinel, recover queued continuation work after crashy restarts, and fall back to a session-only wake when no channel route survives reboot. (#70780) Thanks @fuller-stack-dev.
|
||||
- Agents/tool-result pruning: harden the tool-result character estimator and context-pruning loops against malformed `{ type: "text" }` blocks created by void or undefined tool handler results, serializing non-string text payloads for size accounting so they cannot bypass trimming as zero-sized. Fixes #34979. (#51267) Thanks @cgdusek, @alvinttang, and @coffeexcoin.
|
||||
- Daemon/service-env: add Nix Home Manager profile bin directories to generated gateway service PATHs on macOS and Linux, honoring `NIX_PROFILES` right-to-left precedence and falling back to `~/.nix-profile/bin` when unset. Fixes #44402. (#59935) Thanks @jerome-benoit.
|
||||
- Agents/heartbeat: stop injecting the heartbeat system prompt into non-heartbeat runs, preventing ordinary user replies from being suppressed as `HEARTBEAT_OK` acknowledgments. Fixes #69079. (#69278) Thanks @stainlu.
|
||||
|
||||
## 2026.4.25 (Unreleased)
|
||||
|
||||
|
||||
@@ -6,13 +6,6 @@ describe("shouldInjectHeartbeatPromptForTrigger", () => {
|
||||
expect(shouldInjectHeartbeatPromptForTrigger("heartbeat")).toBe(true);
|
||||
});
|
||||
|
||||
// Regression: the heartbeat system prompt instructs the model to reply
|
||||
// exactly "HEARTBEAT_OK" when nothing is pending. If that prompt leaks into
|
||||
// a user-triggered turn, the model can pattern-match the literal HEARTBEAT_OK
|
||||
// token (which the delivery runtime then suppresses, so the user sees
|
||||
// silence) or hallucinate a "[object Object]" serialization error as it
|
||||
// tries to reconcile the heartbeat instruction with a real user message.
|
||||
// See issue #69079 and its parent #50797.
|
||||
it.each([
|
||||
["user"] as const,
|
||||
["manual"] as const,
|
||||
@@ -24,9 +17,6 @@ describe("shouldInjectHeartbeatPromptForTrigger", () => {
|
||||
});
|
||||
|
||||
it("does not inject the heartbeat prompt when no trigger is supplied", () => {
|
||||
// Defense-in-depth: if a new call site lands without a trigger, it should
|
||||
// fall through to the safe default rather than spuriously injecting
|
||||
// heartbeat instructions.
|
||||
expect(shouldInjectHeartbeatPromptForTrigger(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,14 +4,6 @@ type EmbeddedRunTriggerPolicy = {
|
||||
injectHeartbeatPrompt: boolean;
|
||||
};
|
||||
|
||||
// The heartbeat system prompt tells the model to reply exactly "HEARTBEAT_OK"
|
||||
// when nothing needs attention. It is only meaningful on heartbeat-triggered
|
||||
// runs; injecting it on user/manual/memory/overflow runs confuses smaller
|
||||
// models into pattern-matching the HEARTBEAT_OK output on real user messages
|
||||
// (delivery then suppresses the "reply", so the user sees silence) or into
|
||||
// fabricating "[object Object]" serialization errors as they try to reconcile
|
||||
// the heartbeat instruction with a non-heartbeat turn. See issue #69079 and
|
||||
// its parent #50797. Default off; heartbeat trigger explicitly opts in.
|
||||
const DEFAULT_EMBEDDED_RUN_TRIGGER_POLICY: EmbeddedRunTriggerPolicy = {
|
||||
injectHeartbeatPrompt: false,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user