Skip to content

Commit 8b85130

Browse files
committed
fix: skip timeout-triggered compaction when run was aborted by user
1 parent 800a0d3 commit 8b85130

3 files changed

Lines changed: 24 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
2727

2828
### Fixes
2929

30+
- Agents/compaction: skip timeout-triggered compaction when the run was aborted by the user (Stop button). Previously, user-initiated aborts would still fire timeout compaction if context usage exceeded 65%, causing unnecessary compaction at an inappropriate time. Uses `externalAbort` (set only for user-initiated stops) rather than `aborted` (also set for internal timeouts) to correctly distinguish user aborts from provider timeouts.
3031
- Feishu: return bound subagent delivery origins from session thread setup so Feishu subagent completions route back to the same DM or topic. (#83190) Thanks @100menotu001.
3132
- CLI/update: tailor post-update Gateway recovery hints by platform, showing systemd, LaunchAgent, Scheduled Task, or generic service-manager guidance instead of macOS-only recovery text. (#83096) Thanks @rubencu.
3233
- Plugins: apply a default 15-second timeout to legacy `before_agent_start` hooks so hung plugin handlers no longer block agent startup. Fixes #48534. (#83136) Thanks @therahul-yo.

src/agents/pi-embedded-runner/run.timeout-triggered-compaction.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ describe("timeout-triggered compaction", () => {
371371
makeAttemptResult({
372372
timedOut: true,
373373
aborted: true,
374+
externalAbort: false,
374375
lastAssistant: {
375376
usage: { input: 180000 },
376377
} as never,
@@ -392,6 +393,26 @@ describe("timeout-triggered compaction", () => {
392393
expect(result.meta.error).toBeUndefined();
393394
});
394395

396+
it("does not attempt compaction when user aborted (externalAbort=true)", async () => {
397+
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
398+
makeAttemptResult({
399+
timedOut: true,
400+
aborted: true,
401+
externalAbort: true,
402+
lastAssistant: {
403+
usage: { input: 180000 },
404+
} as never,
405+
}),
406+
);
407+
408+
const result = await runEmbeddedPiAgent(overflowBaseRunParams);
409+
410+
// User-initiated abort should skip timeout compaction entirely
411+
expect(mockedCompactDirect).not.toHaveBeenCalled();
412+
expect(result.payloads?.[0]?.isError).toBe(true);
413+
expect(result.payloads?.[0]?.text).toContain("timed out");
414+
});
415+
395416
it("does not attempt compaction when timedOutDuringCompaction is true", async () => {
396417
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
397418
makeAttemptResult({

src/agents/pi-embedded-runner/run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ export async function runEmbeddedPiAgent(
16881688
// ── Timeout-triggered compaction ──────────────────────────────────
16891689
// When the LLM times out with high context usage, compact before
16901690
// retrying to break the death spiral of repeated timeouts.
1691-
if (timedOut && !timedOutDuringCompaction && !timedOutDuringToolExecution) {
1691+
if (timedOut && !timedOutDuringCompaction && !timedOutDuringToolExecution && !externalAbort) {
16921692
// Only consider prompt-side tokens here. API totals include output
16931693
// tokens, which can make a long generation look like high context
16941694
// pressure even when the prompt itself was small.
@@ -2639,7 +2639,7 @@ export async function runEmbeddedPiAgent(
26392639
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
26402640
});
26412641
const timedOutDuringPrompt =
2642-
timedOut && !timedOutDuringCompaction && !timedOutDuringToolExecution;
2642+
timedOut && !timedOutDuringCompaction && !timedOutDuringToolExecution && !externalAbort;
26432643
const hasPartialAssistantTextAfterPromptTimeout =
26442644
timedOutDuringPrompt &&
26452645
(attempt.assistantTexts ?? []).some((text) => text.trim().length > 0) &&

0 commit comments

Comments
 (0)