openclaw - ✅(Solved) Fix [Bug]: /compact command cannot be canceled while in progress [4 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#66535Fetched 2026-04-15 06:25:44
View on GitHub
Comments
1
Participants
2
Timeline
13
Reactions
0
Author
Participants
Timeline (top)
referenced ×6cross-referenced ×4commented ×1mentioned ×1

/compact invokes runtime.compactEmbeddedPiSession(...) without passing any abortSignal and without registering the compaction session into ACTIVE_EMBEDDED_RUNS. As a result neither chat.abort, abortEmbeddedPiRun(sessionId), nor /stop has any effect on an in-progress /compact; the user has no way to cancel until compactionTimeoutMs expires.

Root Cause

All cancel attempts are no-ops. abortEmbeddedPiRun(sessionId) returns false immediately because the compaction session was never registered. chat.abort similarly finds nothing in chatAbortControllers. The compaction only ends when it completes successfully or when compactionTimeoutMs fires.

Fix Action

Fix / Workaround

  • Affected: any user who invokes /compact on a long-running or complex session.
  • Severity: Medium. No data loss, no crash, but the user is locked out of progress until the compaction or its timeout completes. On slow providers or large sessions this can be several minutes.
  • Frequency: Every /compact that the user wants to abandon — for example when they realize they sent the command prematurely, or when compaction is visibly stuck.
  • Consequence: User frustration, wasted tokens on an unwanted compaction, and in at least one downstream UX (CoClaw UI) an explicit "disable cancel button during /compact" workaround to prevent UI state from diverging from the unkillable server-side operation.

Downstream workaround: UI clients can disable the cancel button while a /compact is in flight, so the user is not misled into expecting cancel to work. The CoClaw UI currently does this via a cancelDisabled prop on its chat input component.

PR fix notes

PR #66569: fix(compact): add cancellation support for /compact command

Description (problem / solution / changelog)

Fixes #66535

The /compact command was not registrable in ACTIVE_EMBEDDED_RUNS and could not be cancelled via standard paths (chat.abort, abortEmbeddedPiRun, /stop).

Root cause: compactEmbeddedPiSession was called without abortSignal and the compaction session was never registered in ACTIVE_EMBEDDED_RUNS.

Changes

  • Create AbortController for compaction session
  • Pass abortSignal to compactEmbeddedPiSession call (existing param)
  • Register compaction in ACTIVE_EMBEDDED_RUNS via setActiveEmbeddedRun
  • Clean up registration when compaction completes
  • Handle interface methods: isStreaming() -> false, isCompacting() -> true

Impact

/compact can now be cancelled via any standard cancellation path, preventing user lockout during long compactions, improving UX for automation

Testing

✅ All existing tests pass ✅ Code follows existing patterns for embedded run management

Changed files

  • extensions/telegram/src/bot-message-context.audio-transcript.test.ts (modified, +22/-0)
  • extensions/telegram/src/bot-message-context.body.ts (modified, +1/-1)
  • extensions/telegram/src/bot-message-context.session.ts (modified, +2/-2)
  • src/agents/bash-tools.exec-approval-followup.test.ts (modified, +19/-0)
  • src/agents/bash-tools.exec-approval-followup.ts (modified, +7/-3)
  • src/auto-reply/reply/commands-compact.ts (modified, +25/-0)
  • src/auto-reply/reply/reply-payloads-base.ts (modified, +1/-4)
  • src/auto-reply/reply/reply-plumbing.test.ts (modified, +14/-0)
  • src/commands/message.test.ts (modified, +47/-0)
  • src/commands/message.ts (modified, +21/-10)
  • ui/src/styles/components.css (modified, +7/-0)

PR #66616: Fix #66535: wire up abort signal for /compact command

Description (problem / solution / changelog)

Summary

Fixes #66535

The /compact command invoked compactEmbeddedPiSession without passing an abortSignal and without registering the compaction session into ACTIVE_EMBEDDED_RUNS. As a result, chat.abort, abortEmbeddedPiRun, and /stop had no effect on an in-progress compaction.

Changes

  • src/auto-reply/reply/commands-compact.ts: Create an AbortController, pass its signal via the already-defined abortSignal field on CompactEmbeddedPiSessionParams, build a minimal EmbeddedPiQueueHandle, and register/unregister with setActiveEmbeddedRun/clearActiveEmbeddedRun.
  • src/auto-reply/reply/commands-compact.runtime.ts: Re-export setActiveEmbeddedRun, clearActiveEmbeddedRun, and EmbeddedPiQueueHandle.
  • src/agents/pi-embedded-runner.ts & src/agents/pi-embedded.ts: Export setActiveEmbeddedRun, clearActiveEmbeddedRun, and EmbeddedPiQueueHandle type.

How it works

  1. Before calling compactEmbeddedPiSession, an AbortController and a minimal EmbeddedPiQueueHandle are created
  2. The handle is registered in ACTIVE_EMBEDDED_RUNS via setActiveEmbeddedRun(sessionId, handle, sessionKey)
  3. The abortSignal is passed through to compactWithSafetyTimeout (which already supports it — see compaction-safety-timeout.ts:62-72)
  4. On completion or error, clearActiveEmbeddedRun removes the handle in a finally block

This allows existing cancel primitives (chat.abort, abortEmbeddedPiRun(sessionId), /stop) to discover and cancel the active compaction.

Testing

  • TypeScript compilation passes for all changed files
  • The two wizard/setup.ts errors in CI are pre-existing and unrelated to this change

Changed files

  • src/agents/pi-embedded-runner.ts (modified, +3/-0)
  • src/agents/pi-embedded.ts (modified, +3/-0)
  • src/auto-reply/reply/commands-compact.runtime.ts (modified, +3/-0)
  • src/auto-reply/reply/commands-compact.ts (modified, +59/-37)
  • src/cli/profile.test.ts (modified, +45/-0)
  • src/cli/profile.ts (modified, +11/-0)

PR #66623: Fix #66535: wire up abort signal for /compact command

Description (problem / solution / changelog)

Summary

Fixes #66535

The /compact command invoked compactEmbeddedPiSession without passing an abortSignal and without registering the compaction session into ACTIVE_EMBEDDED_RUNS. As a result, chat.abort, abortEmbeddedPiRun, and /stop had no effect on an in-progress compaction.

Changes

  • src/auto-reply/reply/commands-compact.ts:
    • Check that the previous embedded run fully drained before registering the compaction handle, returning a retry prompt if it has not
    • Create an AbortController, pass its signal via the already-defined abortSignal field on CompactEmbeddedPiSessionParams
    • Build a minimal EmbeddedPiQueueHandle and register/unregister with setActiveEmbeddedRun/clearActiveEmbeddedRun
  • src/auto-reply/reply/commands-compact.runtime.ts: Re-export setActiveEmbeddedRun, clearActiveEmbeddedRun, and EmbeddedPiQueueHandle.
  • src/agents/pi-embedded-runner.ts & src/agents/pi-embedded.ts: Export setActiveEmbeddedRun, clearActiveEmbeddedRun, and EmbeddedPiQueueHandle type.

How it works

  1. Abort any existing run and wait for it to fully drain; if it doesn't, return a retry prompt instead of overwriting the handle
  2. Create an AbortController and a minimal EmbeddedPiQueueHandle
  3. Register the handle in ACTIVE_EMBEDDED_RUNS via setActiveEmbeddedRun(sessionId, handle, sessionKey)
  4. Pass the abortSignal through to compactWithSafetyTimeout (which already supports it)
  5. On completion or error, clearActiveEmbeddedRun removes the handle in a finally block

Testing

  • TypeScript compilation passes for all changed files
  • The wizard/setup.ts errors are pre-existing and unrelated

Changed files

  • src/auto-reply/reply/commands-compact.ts (modified, +66/-38)
  • src/cli/profile.test.ts (modified, +45/-0)
  • src/cli/profile.ts (modified, +11/-0)

PR #66894: Fix #66535: wire up abort signal for /compact command

Description (problem / solution / changelog)

Summary

Fixes #66535

The /compact command invoked compactEmbeddedPiSession without passing an abortSignal and without registering the compaction session into ACTIVE_EMBEDDED_RUNS. As a result, chat.abort, abortEmbeddedPiRun, and /stop had no effect on an in-progress compaction.

Changes

  • Barrel exports (pi-embedded-runner.ts, pi-embedded.ts, commands-compact.runtime.ts): Export setActiveEmbeddedRun, clearActiveEmbeddedRun, and EmbeddedPiQueueHandle type
  • commands-compact.ts:
    • Guard: only register after confirming the previous run has fully drained via waitForEmbeddedPiRunEnd; return a retry prompt if timed out
    • Create an AbortController, pass its signal to compactEmbeddedPiSession via the existing abortSignal field
    • Register a minimal EmbeddedPiQueueHandle in ACTIVE_EMBEDDED_RUNS before starting
    • Handle compaction errors (including abort) via try/catch/finally; clean up handle in finally

Testing

  • TypeScript compilation passes for all changed files
  • wizard/setup.ts errors are pre-existing and unrelated

Changed files

  • src/agents/pi-embedded-runner.ts (modified, +3/-0)
  • src/agents/pi-embedded-runner/compact.queued.ts (modified, +40/-0)
  • src/agents/pi-embedded.ts (modified, +3/-0)
  • src/auto-reply/reply/commands-compact.ts (modified, +8/-1)
  • src/cli/profile.test.ts (modified, +45/-0)
  • src/cli/profile.ts (modified, +11/-0)

Code Example

abortSignal?: AbortSignal;
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

/compact invokes runtime.compactEmbeddedPiSession(...) without passing any abortSignal and without registering the compaction session into ACTIVE_EMBEDDED_RUNS. As a result neither chat.abort, abortEmbeddedPiRun(sessionId), nor /stop has any effect on an in-progress /compact; the user has no way to cancel until compactionTimeoutMs expires.

Steps to reproduce

  1. Start OpenClaw on a session that has accumulated enough messages for /compact to take tens of seconds or longer.
  2. In the chat, send /compact.
  3. While compaction is running, attempt to cancel via any available path: chat.abort, abortEmbeddedPiRun(sessionId) (directly or via the globalThis[Symbol.for("openclaw.embeddedRunState")].activeRuns.get(sessionId).abort() side door), or /stop.
  4. Observe that the compaction continues regardless.

Expected behavior

Invoking any supported cancel path should interrupt the compaction within a few seconds, consistent with any other embedded agent run. The compaction session should also appear in ACTIVE_EMBEDDED_RUNS for the duration, so external observers can discover it.

Actual behavior

All cancel attempts are no-ops. abortEmbeddedPiRun(sessionId) returns false immediately because the compaction session was never registered. chat.abort similarly finds nothing in chatAbortControllers. The compaction only ends when it completes successfully or when compactionTimeoutMs fires.

OpenClaw version

2026.4.12

Operating system

Ubuntu 22.04.5 LTS on WSL2 (Linux 6.6.87.2-microsoft-standard-WSL2)

Install method

npm global

Model

N/A (compaction uses whatever model the session is configured with; the cancel bug is independent of model selection)

Provider / routing chain

N/A (cancel path is orthogonal to provider routing)

Additional provider/model setup details

N/A

Logs, screenshots, and evidence

src/auto-reply/reply/commands-compact.ts (the current /compact handler, approximately L72-145): the handler first invokes abortEmbeddedPiRun(sessionId) + waitForEmbeddedPiRunEnd(sessionId, 15_000) to stop the current run, then calls runtime.compactEmbeddedPiSession({...}) without an abortSignal argument and without calling setActiveEmbeddedRun for the compaction itself.

The type definition in src/agents/pi-embedded-runner/compact.types.ts:56 already declares:

abortSignal?: AbortSignal;

on CompactEmbeddedPiSessionParams, so the parameter surface is prepared; the command path is simply not wiring it up. src/agents/pi-embedded-runner/compact.ts:520 (prepareCompactionSessionAgent) already passes an internal runAbortController.signal to a sub-session, so the inner mechanics exist.

Impact and severity

  • Affected: any user who invokes /compact on a long-running or complex session.
  • Severity: Medium. No data loss, no crash, but the user is locked out of progress until the compaction or its timeout completes. On slow providers or large sessions this can be several minutes.
  • Frequency: Every /compact that the user wants to abandon — for example when they realize they sent the command prematurely, or when compaction is visibly stuck.
  • Consequence: User frustration, wasted tokens on an unwanted compaction, and in at least one downstream UX (CoClaw UI) an explicit "disable cancel button during /compact" workaround to prevent UI state from diverging from the unkillable server-side operation.

Additional information

Minimum fix: in commands-compact.ts, construct an AbortController, pass its signal via the already-defined abortSignal field on CompactEmbeddedPiSessionParams, and register the compaction into ACTIVE_EMBEDDED_RUNS via setActiveEmbeddedRun(sessionId, handle, sessionKey) so that existing cancel primitives (chat.abort, abortEmbeddedPiRun) find it. The bulk of the type and inner-session plumbing is already in place.

Downstream workaround: UI clients can disable the cancel button while a /compact is in flight, so the user is not misled into expecting cancel to work. The CoClaw UI currently does this via a cancelDisabled prop on its chat input component.

Verified against OpenClaw commit d7cc6f7643 (v2026.4.14-beta.1+69).


Reported by the CoClaw team. This issue was discovered while developing @coclaw/openclaw-coclaw, a CoClaw channel plugin for OpenClaw.

extent analysis

TL;DR

Passing an abortSignal to runtime.compactEmbeddedPiSession and registering the compaction session in ACTIVE_EMBEDDED_RUNS should enable cancellation of in-progress compactions.

Guidance

  • Construct an AbortController in commands-compact.ts to generate an abortSignal for the compaction session.
  • Pass the abortSignal via the abortSignal field on CompactEmbeddedPiSessionParams when calling runtime.compactEmbeddedPiSession.
  • Register the compaction session in ACTIVE_EMBEDDED_RUNS using setActiveEmbeddedRun(sessionId, handle, sessionKey) to allow existing cancel primitives to find and interrupt it.
  • Consider disabling the cancel button in UI clients while a compaction is in progress to prevent user confusion.

Example

const abortController = new AbortController();
const compactParams: CompactEmbeddedPiSessionParams = {
  // ... other params ...
  abortSignal: abortController.signal,
};
runtime.compactEmbeddedPiSession(compactParams);
setActiveEmbeddedRun(sessionId, handle, sessionKey);

Notes

This fix assumes that the AbortController and ACTIVE_EMBEDDED_RUNS mechanisms are correctly implemented and functional in the OpenClaw codebase.

Recommendation

Apply the workaround by passing an abortSignal and registering the compaction session, as this enables cancellation of in-progress compactions without requiring a version upgrade.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Invoking any supported cancel path should interrupt the compaction within a few seconds, consistent with any other embedded agent run. The compaction session should also appear in ACTIVE_EMBEDDED_RUNS for the duration, so external observers can discover it.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: /compact command cannot be canceled while in progress [4 pull requests, 1 comments, 2 participants]