fix(agents): preserve cron heartbeat suppression during compaction#53468
fix(agents): preserve cron heartbeat suppression during compaction#53468Protocol-zero-0 wants to merge 2 commits intoopenclaw:mainfrom
Conversation
Carry the original embedded-run trigger into overflow compaction so cron-origin sessions do not regain the heartbeat prompt when the system prompt is rebuilt. Made-with: Cursor
Greptile SummaryThis PR correctly propagates the original run trigger ( Changes:
Issues found:
Confidence Score: 5/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/pi-embedded-runner/compact.hooks.test.ts
Line: 120-133
Comment:
**Misleading test description and assertion**
The second assertion in this test — `{ isDefaultAgent: false, sourceTrigger: "cron" }` → `false` — returns `false` because `isDefaultAgent` is `false`, not because the trigger is non-cron. It doesn't validate the "preserves heartbeat prompt rebuilds for non-cron compaction" claim stated in the test title, and actually contradicts the "preserves" framing (the heartbeat prompt is not injected here). Consider splitting this into its own test that describes what it actually covers:
```suggestion
it("preserves heartbeat prompt rebuilds for non-cron compaction", () => {
expect(
compactTesting.shouldInjectHeartbeatPromptDuringCompaction({
isDefaultAgent: true,
sourceTrigger: "memory",
}),
).toBe(true);
});
it("does not inject heartbeat prompt for non-default agents", () => {
expect(
compactTesting.shouldInjectHeartbeatPromptDuringCompaction({
isDefaultAgent: false,
sourceTrigger: "cron",
}),
).toBe(false);
});
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(agents): preserve cron heartbeat sup..." | Re-trigger Greptile |
| it("preserves heartbeat prompt rebuilds for non-cron compaction", () => { | ||
| expect( | ||
| compactTesting.shouldInjectHeartbeatPromptDuringCompaction({ | ||
| isDefaultAgent: true, | ||
| sourceTrigger: "memory", | ||
| }), | ||
| ).toBe(true); | ||
| expect( | ||
| compactTesting.shouldInjectHeartbeatPromptDuringCompaction({ | ||
| isDefaultAgent: false, | ||
| sourceTrigger: "cron", | ||
| }), | ||
| ).toBe(false); | ||
| }); |
There was a problem hiding this comment.
Misleading test description and assertion
The second assertion in this test — { isDefaultAgent: false, sourceTrigger: "cron" } → false — returns false because isDefaultAgent is false, not because the trigger is non-cron. It doesn't validate the "preserves heartbeat prompt rebuilds for non-cron compaction" claim stated in the test title, and actually contradicts the "preserves" framing (the heartbeat prompt is not injected here). Consider splitting this into its own test that describes what it actually covers:
| it("preserves heartbeat prompt rebuilds for non-cron compaction", () => { | |
| expect( | |
| compactTesting.shouldInjectHeartbeatPromptDuringCompaction({ | |
| isDefaultAgent: true, | |
| sourceTrigger: "memory", | |
| }), | |
| ).toBe(true); | |
| expect( | |
| compactTesting.shouldInjectHeartbeatPromptDuringCompaction({ | |
| isDefaultAgent: false, | |
| sourceTrigger: "cron", | |
| }), | |
| ).toBe(false); | |
| }); | |
| it("preserves heartbeat prompt rebuilds for non-cron compaction", () => { | |
| expect( | |
| compactTesting.shouldInjectHeartbeatPromptDuringCompaction({ | |
| isDefaultAgent: true, | |
| sourceTrigger: "memory", | |
| }), | |
| ).toBe(true); | |
| }); | |
| it("does not inject heartbeat prompt for non-default agents", () => { | |
| expect( | |
| compactTesting.shouldInjectHeartbeatPromptDuringCompaction({ | |
| isDefaultAgent: false, | |
| sourceTrigger: "cron", | |
| }), | |
| ).toBe(false); | |
| }); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/compact.hooks.test.ts
Line: 120-133
Comment:
**Misleading test description and assertion**
The second assertion in this test — `{ isDefaultAgent: false, sourceTrigger: "cron" }` → `false` — returns `false` because `isDefaultAgent` is `false`, not because the trigger is non-cron. It doesn't validate the "preserves heartbeat prompt rebuilds for non-cron compaction" claim stated in the test title, and actually contradicts the "preserves" framing (the heartbeat prompt is not injected here). Consider splitting this into its own test that describes what it actually covers:
```suggestion
it("preserves heartbeat prompt rebuilds for non-cron compaction", () => {
expect(
compactTesting.shouldInjectHeartbeatPromptDuringCompaction({
isDefaultAgent: true,
sourceTrigger: "memory",
}),
).toBe(true);
});
it("does not inject heartbeat prompt for non-default agents", () => {
expect(
compactTesting.shouldInjectHeartbeatPromptDuringCompaction({
isDefaultAgent: false,
sourceTrigger: "cron",
}),
).toBe(false);
});
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Pull request overview
This PR fixes embedded agent compaction behavior so that cron-triggered runs keep cron-specific prompt policies even when an overflow compaction rebuild occurs (i.e., compaction no longer “forgets” the original run trigger).
Changes:
- Propagate the original embedded-run trigger into overflow-compaction runtimeContext (
sourceTrigger). - Update compaction prompt construction to suppress heartbeat prompt reinjection based on the original trigger (not just the compaction trigger).
- Add regression tests for the compaction heartbeat prompt policy.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/agents/pi-embedded-runner/run.ts |
Adds sourceTrigger to overflow compaction runtime context so downstream compaction logic can apply original-trigger policies. |
src/agents/pi-embedded-runner/compact.ts |
Uses sourceTrigger + trigger policy to decide whether to inject the heartbeat prompt during compaction rebuilds. |
src/agents/pi-embedded-runner/compact.hooks.test.ts |
Adds unit coverage for the new compaction heartbeat injection policy behavior. |
| runId: params.runId, | ||
| trigger: "overflow", | ||
| sourceTrigger: params.trigger, | ||
| ...(observedOverflowTokens !== undefined |
There was a problem hiding this comment.
The new sourceTrigger propagation in the overflow-compaction runtimeContext isn’t covered by existing overflow-compaction regression tests. Please add/extend a test (e.g., in run.overflow-compaction.test.ts) to assert that when a run is triggered by cron and overflow recovery compaction happens, the compaction runtimeContext includes sourceTrigger: "cron" (so downstream prompt rebuild policy is actually exercised end-to-end).
fabianwilliams
left a comment
There was a problem hiding this comment.
Clean fix, directly relevant to real-world cron workloads.
What I like:
- Threading
sourceTriggerthrough overflow compaction is the right approach — the trigger context should survive the full session lifecycle, not just the initial run. - The
shouldInjectHeartbeatPromptDuringCompactionwrapper keeps the decision logic in one place instead of scattering conditionals. - Test coverage is solid — both the suppression case (cron trigger) and the preservation case (non-cron trigger) are covered, and the
isDefaultAgent: false+sourceTrigger: "cron"combo correctly returnsfalse.
One question:
The sourceTrigger param in CompactEmbeddedPiSessionParams is optional (sourceTrigger?: EmbeddedRunTrigger). If sourceTrigger is undefined (e.g., compaction triggered from a code path that doesn't set it), shouldInjectHeartbeatPromptForTrigger(undefined) falls through to the default policy (inject = true). That's safe, but worth a comment in the code noting that the undefined case intentionally falls through to "inject heartbeat" as the conservative default.
Otherwise LGTM — this fixes a real pain point for anyone running cron-heavy OpenClaw setups.
Document the conservative sourceTrigger fallback and tighten the regression coverage around overflow compaction so the cron trigger propagation remains obvious to reviewers and future maintainers. Made-with: Cursor
|
Follow-up pushed in
That should cover both the wording nit and the missing regression-path coverage. |
Summary
Test plan
pnpm exec vitest run src/agents/pi-embedded-runner/compact.hooks.test.ts src/agents/pi-embedded-runner/run/attempt.test.tspnpm checkMade with Cursor