Skip to content

🤖 refactor: move auto-compaction & auto-retry from frontend to backend#2469

Open
ThomasK33 wants to merge 52 commits intomainfrom
compaction-k3gj
Open

🤖 refactor: move auto-compaction & auto-retry from frontend to backend#2469
ThomasK33 wants to merge 52 commits intomainfrom
compaction-k3gj

Conversation

@ThomasK33
Copy link
Member

Summary

Moves three autonomous behaviors from the frontend (React hooks + localStorage) to the backend (AgentSession), making the backend the single source of truth for "what happens next in a turn":

  1. Auto-retryRetryManager in AgentSession handles exponential backoff retry of failed streams
  2. Idle compactionIdleCompactionService executes compaction directly instead of asking the frontend
  3. On-send & mid-stream compactionCompactionMonitor in AgentSession checks context usage before sending and during streaming, triggering compaction automatically

Background

The frontend previously acted as the orchestrator for auto-retry (via useResumeManager) and auto-compaction (via useForceCompaction, useIdleCompactionHandler, and pre-send checks in ChatInput). This created fragility: retries and compactions didn't survive page reloads, race conditions existed between frontend and backend state, and the frontend contained complex state machines that belong in the backend.

Implementation

Phase 1 — Auto-Retry → Backend:

  • Extracted retryEligibility.ts and retryState.ts from browser/ to common/
  • Created RetryManager class with backoff scheduling, non-retryable error detection, cancel/dispose
  • Integrated into AgentSession: stream-end → handleStreamSuccess(), stream-error → handleStreamFailure()
  • Added setAutoRetryEnabled IPC route
  • New chat events: auto-retry-scheduled, auto-retry-starting, auto-retry-abandoned
  • Removed useResumeManager hook and autoRetryPreference localStorage wrapper

Phase 2 — Idle Compaction → Backend:

  • Extracted buildCompactionMessageText() to common/utils/compaction/compactionPrompt.ts
  • IdleCompactionService now calls workspaceService.executeIdleCompaction() directly
  • Cross-workspace serialization preserved via internal queue
  • New chat event: idle-compaction-started (replaces idle-compaction-needed)
  • Removed useIdleCompactionHandler hook

Phase 3 — On-Send & Mid-Stream Compaction → Backend:

  • Extracted autoCompactionCheck.ts and contextLimit.ts from browser/ to common/
  • Created CompactionMonitor class with threshold checks and single-trigger-per-stream guard
  • Integrated into AgentSession: pre-send check synthesizes compaction request with follow-up, mid-stream check interrupts and chains compaction
  • Added setAutoCompactionThreshold IPC route
  • New chat events: auto-compaction-triggered, auto-compaction-completed
  • Removed useForceCompaction hook and shouldTriggerAutoCompaction pre-send check

Phase 4 — Cleanup:

  • Removed dead localStorage key helpers (getAutoRetryKey, getRetryStateKey)
  • Renamed MuxFrontendMetadataMuxMessageMetadata (no longer frontend-specific)
  • Fixed all lint and formatting issues

Risks

  • Medium: The backend now drives retry/compaction timing — if AgentSession crashes mid-retry, state is lost (acceptable: fresh start on restart, same as before)
  • Low: Provider config overrides for custom context windows are passed as null in session-side monitor checks (existing SendMessageOptions doesn't carry providers config map). A follow-up can thread this for full parity.
  • Low: Frontend CompactionWarning is now informational-only (backend handles the action)

📋 Implementation Plan

Move Auto-Compaction & Auto-Retry from Frontend to Backend

Context & Why

Today, the frontend (React hooks + localStorage) acts as the orchestrator for two critical autonomous behaviors:

  1. Auto-compaction — detecting when context usage is too high and synthesizing /compact turns (on-send, mid-stream, and idle).
  2. Auto-retry — detecting interrupted streams and resuming them with exponential backoff.

This creates fragility: retries and compactions don't survive page reloads, race conditions exist between frontend state and backend state, and the frontend contains complex state machines that belong in the backend. Moving this logic into AgentSession makes the backend the single source of truth for "what happens next in a turn."

Evidence

Source What it told us
src/browser/hooks/useResumeManager.ts Retry orchestrator: polls every 1s, exponential backoff (1s→60s), persists RetryState to localStorage
src/browser/utils/messages/retryEligibility.ts Classification: non-retryable errors list, grace period (15s), isEligibleForAutoRetry()
src/browser/utils/messages/retryState.ts Backoff math: min(1000 * 2^attempt, 60000)
src/browser/utils/compaction/autoCompactionCheck.ts Threshold check: warning at threshold−10%, force at threshold+5%
src/browser/hooks/useForceCompaction.ts Mid-stream: monitors shouldForceCompact, interrupts stream, triggers compaction
src/browser/hooks/useIdleCompactionHandler.ts Idle: listens for idle-compaction-needed, serializes queue, calls sendMessage
src/browser/utils/chatCommands.ts executeCompaction() builds metadata with type: "compaction-request" and calls sendMessage
src/node/services/agentSession.ts Already has TurnPhase (IDLE→PREPARING→STREAMING→COMPLETING→IDLE), streamWithHistory, and compaction follow-up dispatch
src/node/services/compactionHandler.ts handleCompletion() already processes compaction results and returns boolean to signal follow-up dispatch
src/node/services/idleCompactionService.ts Already detects idle workspaces and emits events; just doesn't execute the compaction itself
src/node/services/streamManager.ts Has per-workspace mutex, existing retry for previous_response_not_found
src/common/types/message.ts CompactionRequestData, MuxFrontendMetadata, CompactionFollowUpRequest already defined
src/common/orpc/schemas/stream.ts WorkspaceChatMessage union already includes idle-compaction-needed variant
src/browser/stores/WorkspaceStore.ts Retry state reset happens here on stream-end

Architecture Overview

The core change: AgentSession gains a post-turn decision loop that can chain compaction or retry turns without frontend involvement.

Current:  Frontend polls/decides → IPC call → Backend executes one turn → returns
Proposed: Frontend sends message  → Backend executes turn → Backend decides next action
                                                           → auto-retry? loop internally
                                                           → needs compaction? chain compaction turn
                                                           → done? emit stream-end to frontend

The frontend becomes a thin display layer that shows status events ("retrying attempt 2/5…", "auto-compacting…") rather than driving the state machine.


Phase 1: Move Auto-Retry into Backend

Goal: AgentSession automatically retries failed streams with exponential backoff. Frontend useResumeManager is removed.

~350 LoC added (backend), ~400 LoC removed (frontend). Net: −50 LoC.

1.1 Extract shared retry utilities to src/common/

Move pure logic from frontend to common (no DOM/React dependencies):

  • src/browser/utils/messages/retryEligibility.tssrc/common/utils/messages/retryEligibility.ts

    • isEligibleForAutoRetry() — adapt signature to work with MuxMessage[] instead of DisplayedMessage[]
    • NON_RETRYABLE_STREAM_ERRORS, NON_RETRYABLE_SEND_ERRORS — export as-is
    • isNonRetryableSendError(), isNonRetryableStreamError() — export as-is
  • src/browser/utils/messages/retryState.tssrc/common/utils/messages/retryState.ts

    • RetryState interface, calculateBackoffDelay(), createFreshRetryState(), createFailedRetryState()
    • Remove createManualRetryState() (manual retries become just another resumeStream call)

Update all existing frontend imports to point to src/common/....

1.2 Add RetryManager to AgentSession

New file: src/node/services/retryManager.ts

import { RetryState, calculateBackoffDelay, createFreshRetryState, createFailedRetryState } from "@/common/utils/messages/retryState";
import { isNonRetryableStreamError, isNonRetryableSendError } from "@/common/utils/messages/retryEligibility";

export class RetryManager {
  private state: RetryState = createFreshRetryState();
  private retryTimer: ReturnType<typeof setTimeout> | null = null;
  private enabled = true; // user preference

  constructor(
    private readonly workspaceId: string,
    private readonly onRetry: () => Promise<void>,
    private readonly onStatusChange: (event: RetryStatusEvent) => void,
  ) {}

  /** Called after a stream fails. Decides whether to retry. */
  handleStreamFailure(error: SendMessageError): void {
    if (!this.enabled) return;
    if (isNonRetryableSendError(error) || isNonRetryableStreamError(error)) {
      this.onStatusChange({ type: "retry-abandoned", reason: error.type });
      return;
    }

    this.state = createFailedRetryState(this.state.attempt, error);
    const delay = calculateBackoffDelay(this.state.attempt);
    
    this.onStatusChange({
      type: "retry-scheduled",
      attempt: this.state.attempt,
      delayMs: delay,
    });

    this.retryTimer = setTimeout(async () => {
      this.onStatusChange({ type: "retry-starting", attempt: this.state.attempt });
      await this.onRetry();
    }, delay);
  }

  /** Called when a stream succeeds — resets state. */
  handleStreamSuccess(): void {
    this.state = createFreshRetryState();
  }

  /** Called on user Ctrl+C or explicit cancel. */
  cancel(): void {
    if (this.retryTimer) clearTimeout(this.retryTimer);
    this.retryTimer = null;
    this.state = createFreshRetryState();
  }

  setEnabled(enabled: boolean): void { this.enabled = enabled; }
  dispose(): void { this.cancel(); }
}

1.3 Integrate RetryManager into AgentSession

In src/node/services/agentSession.ts:

  • Instantiate RetryManager in constructor, wire onRetry to call this.resumeStream()
  • Wire onStatusChange to emit new chat events (see §1.4)
  • In the stream-end handler (line ~1772): call retryManager.handleStreamSuccess()
  • In error paths (stream-abort, stream-error): call retryManager.handleStreamFailure(error)
  • In interrupt() method: call retryManager.cancel() (user explicitly stopped)
  • Add setAutoRetryEnabled(enabled: boolean) method, called from IPC when user toggles preference

1.4 New chat event types

In src/common/orpc/schemas/stream.ts, add to the WorkspaceChatMessage union:

// New variants
| { type: "auto-retry-scheduled"; attempt: number; delayMs: number; maxDelay: number }
| { type: "auto-retry-starting"; attempt: number }
| { type: "auto-retry-abandoned"; reason: string }

1.5 New IPC method for retry preference

In src/node/orpc/router.ts, add:

workspace.setAutoRetryEnabled.input(z.object({
  workspaceId: z.string(),
  enabled: z.boolean(),
}))

This replaces the current localStorage-based autoRetryPreference.ts.

1.6 Frontend cleanup

Remove:

  • src/browser/hooks/useResumeManager.ts — entire file
  • src/browser/utils/messages/autoRetryPreference.ts — replaced by IPC call
  • src/browser/utils/messages/retryState.ts — moved to common (update imports)
  • src/browser/utils/messages/retryEligibility.ts — moved to common (update imports)
  • localStorage keys for retry state in WorkspaceStore.ts (line ~438)

Update:

  • src/browser/stores/WorkspaceStore.ts — handle new auto-retry-scheduled/starting/abandoned events, update workspace state for UI display
  • src/browser/components/Messages/ChatBarrier/RetryBarrier.tsx — show "Backend retrying (attempt N)…" status from store state instead of driving retries
  • ChatPane.tsx or wherever useResumeManager is mounted — remove the hook call

Phase 2: Move Idle Compaction Execution to Backend

Goal: When IdleCompactionService detects an idle workspace, the backend executes the compaction itself instead of asking the frontend.

~100 LoC added (backend), ~150 LoC removed (frontend). Net: −50 LoC.

2.1 Backend: IdleCompactionService executes directly

In src/node/services/idleCompactionService.ts (or workspaceService.ts):

  • Instead of emitting idle-compaction-needed, call agentSession.sendMessage() directly with the compaction metadata
  • The compaction message is built the same way executeCompaction does in the frontend — construct muxMetadata with type: "compaction-request" and source: "idle-compaction"
  • Serialize across workspaces using the existing per-workspace AsyncMutex in StreamManager (natural serialization — only one stream per workspace at a time)
  • For cross-workspace serialization (avoid thundering herd), add a simple queue in IdleCompactionService itself (mirrors the queueRef logic from useIdleCompactionHandler)

2.2 New chat event for status

Add to WorkspaceChatMessage:

| { type: "idle-compaction-started" }

The existing idle-compaction-needed event can be kept for backwards compatibility (frontend shows a notification) or removed if the frontend no longer needs to know about idle compaction until it's happening. Recommend: replace with idle-compaction-started so the frontend can show "Compacting idle workspace…" status.

2.3 Build compaction prompt in backend

Extract from src/browser/utils/chatCommands.ts (prepareCompactionMessage):

  • The prompt text construction (buildCompactionPrompt) — move to src/common/utils/compaction/ or src/node/services/
  • The metadata construction (muxMetadata with type: "compaction-request", source, displayStatus) — this is already defined in src/common/types/message.ts, so the backend can construct it directly

2.4 Frontend cleanup

Remove:

  • src/browser/hooks/useIdleCompactionHandler.ts — entire file
  • Remove mounting of useIdleCompactionHandler from the app root component
  • Remove idle-compaction-needed event handling from WorkspaceStore.ts (or replace with idle-compaction-started handler)

Phase 3: Move On-Send & Mid-Stream Compaction to Backend

Goal: The backend automatically compacts when context usage exceeds thresholds, without frontend involvement. This is the largest change.

~250 LoC added (backend), ~300 LoC removed (frontend). Net: −50 LoC.

3.1 Extract compaction threshold logic to src/common/

Move from src/browser/utils/compaction/autoCompactionCheck.ts to src/common/utils/compaction/autoCompactionCheck.ts:

  • checkAutoCompaction() — adapt to take raw token counts + model info rather than frontend store types
  • getContextTokens() — pure math, moves as-is
  • getEffectiveContextLimit() from src/browser/utils/compaction/contextLimit.ts — already only depends on model stats, move to common

3.2 Add CompactionMonitor to AgentSession

New file: src/node/services/compactionMonitor.ts

export class CompactionMonitor {
  private threshold = 0.70; // default, configurable
  private hasTriggeredForCurrentStream = false;

  constructor(
    private readonly workspaceId: string,
    private readonly onCompactionNeeded: (reason: "on-send" | "mid-stream") => Promise<void>,
    private readonly onStatusChange: (event: CompactionStatusEvent) => void,
  ) {}

  /** Called before sending a new message. Returns true if compaction should happen first. */
  checkBeforeSend(usage: TokenUsage, contextLimit: number): boolean {
    const pct = (usage.input + usage.cached + usage.cacheCreate) / contextLimit;
    return pct >= this.threshold;
  }

  /** Called on each usage-delta during streaming. Triggers mid-stream compaction if needed. */
  handleUsageDelta(usage: TokenUsage, contextLimit: number): void {
    if (this.hasTriggeredForCurrentStream) return;
    const pct = (usage.input + usage.cached + usage.cacheCreate) / contextLimit;
    const forceThreshold = this.threshold + 0.05;
    if (pct >= forceThreshold) {
      this.hasTriggeredForCurrentStream = true;
      this.onStatusChange({ type: "force-compaction-triggered", usagePercent: pct });
      this.onCompactionNeeded("mid-stream");
    }
  }

  resetForNewStream(): void { this.hasTriggeredForCurrentStream = false; }
  setThreshold(threshold: number): void { this.threshold = threshold; }
}

3.3 Integrate into AgentSession

In src/node/services/agentSession.ts:

On-send compaction:

  • In sendMessage(), before calling streamWithHistory(), call compactionMonitor.checkBeforeSend()
  • If true: synthesize a compaction message with the user's original message as followUpContent (same as the frontend's executeCompaction does today), then call streamWithHistory() with the compaction request
  • The existing compactionHandler.handleCompletion()dispatchPendingFollowUp() flow handles sending the original message after compaction finishes — this already works today

Mid-stream compaction:

  • In the usage-delta event handler, call compactionMonitor.handleUsageDelta()
  • If triggered: interrupt the current stream (this.interrupt()), then chain a compaction turn followed by a [CONTINUE] resume — reusing the existing compaction-then-follow-up infrastructure

3.4 Threshold preference via IPC

In src/node/orpc/router.ts, add:

workspace.setAutoCompactionThreshold.input(z.object({
  workspaceId: z.string(),
  threshold: z.number().min(0.1).max(1.0),
}))

The frontend's ContextUsageIndicatorButton slider calls this instead of persisting locally. The backend stores the threshold on AgentSession (or a workspace config object).

3.5 New chat events

| { type: "auto-compaction-started"; reason: "on-send" | "mid-stream" | "idle"; usagePercent: number }
| { type: "auto-compaction-completed"; newUsagePercent: number }

3.6 Frontend cleanup

Remove:

  • src/browser/hooks/useForceCompaction.ts — entire file
  • Auto-compaction check in src/browser/components/ChatInput/index.tsx — the shouldTriggerAutoCompaction pre-send check
  • autoCompactionResult computation in ChatPane.tsx — no longer needed for driving compaction (may still be needed for the warning banner UI)
  • src/browser/utils/compaction/autoCompactionCheck.ts — moved to common (update imports)

Keep (modified):

  • CompactionWarning.tsx — can still show "context usage is high" based on usage-delta events from the store, but it becomes informational rather than actionable (the backend handles it automatically)
  • ContextUsageIndicatorButton — slider still exists, but calls IPC to set threshold on backend instead of persisting locally

Phase 4: Clean Up & Polish

~Net −100 LoC (removing dead code, consolidating types).

4.1 Remove dead frontend-to-backend compaction path

  • The frontend no longer calls sendMessage with type: "compaction-request" metadata — all compaction is backend-initiated
  • Remove executeCompaction and prepareCompactionMessage from src/browser/utils/chatCommands.ts
  • Remove formatCompactionCommandLine if no longer used

4.2 Consolidate types

  • MuxFrontendMetadata in src/common/types/message.ts — the "compaction-request" variant is now backend-internal; consider renaming to MuxMessageMetadata since it's no longer frontend-specific
  • CompactionFollowUpRequest — now constructed entirely by the backend

4.3 Update tests

  • Backend tests: Add tests for RetryManager (backoff, non-retryable errors, cancel) and CompactionMonitor (threshold checks, mid-stream trigger, reset)
  • Integration tests: Verify that AgentSession auto-retries on transient errors and auto-compacts on threshold breach
  • Frontend tests: Update any tests that depend on useResumeManager, useForceCompaction, or useIdleCompactionHandler

4.4 Manual user-triggered /compact still works

The user can still type /compact in chat input → the frontend sends it as a regular sendMessage with type: "compaction-request" metadata → the backend processes it as before. This path doesn't change.


Execution Order & Dependencies

graph TD
    A["Phase 1: Auto-Retry → Backend"] --> C["Phase 3: On-Send + Mid-Stream Compaction → Backend"]
    B["Phase 2: Idle Compaction → Backend"] --> C
    C --> D["Phase 4: Cleanup & Polish"]
    style A fill:#4CAF50,color:#fff
    style B fill:#4CAF50,color:#fff
    style C fill:#FF9800,color:#fff
    style D fill:#2196F3,color:#fff
Loading
  • Phases 1 and 2 are independent — can be done in parallel by separate agents.
  • Phase 3 depends on both — it needs the shared utilities extracted in Phase 1 and the backend compaction execution pattern from Phase 2.
  • Phase 4 is cleanup — depends on all prior phases.

Risk Mitigation

Risk Mitigation
User loses ability to cancel during auto-retry/compaction interrupt() already cancels active streams; RetryManager.cancel() clears pending timers. Frontend sends interrupt IPC as before.
Threshold preferences out of sync Backend is authoritative; frontend reads from backend via workspace state events, writes via IPC.
Crash during auto-retry loop RetryManager state is in-memory only; on crash, AgentSession restarts fresh. The existing resumeStream path on app restart handles recovery.
Backend compaction races with user input StreamManager mutex ensures one stream per workspace. Queued user messages are held until the compaction turn completes (existing sendQueuedMessages behavior).

Total Estimated Impact

Phase Backend LoC Frontend LoC Net
Phase 1: Auto-Retry +350 −400 −50
Phase 2: Idle Compaction +100 −150 −50
Phase 3: On-Send/Mid-Stream +250 −300 −50
Phase 4: Cleanup +0 −100 −100
Total +700 −950 −250

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $4.01

@ThomasK33
Copy link
Member Author

@codex review

@ThomasK33
Copy link
Member Author

@codex review

Rebased onto main and resolved conflicts. All static checks (typecheck, lint, fmt-check) and targeted tests pass.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd1f8f9f16

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed the failing integration tests for backend-driven compaction. All static checks pass locally.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3967369f54

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed P1 feedback:

  • setEnabled(false) now cancels pending retry timer AND emits auto-retry-abandoned event so frontend clears retry status
  • Replaced hard assertion on duplicate failures with graceful cancel+reschedule (fixes integration test crash)
  • Added test coverage for both behaviors

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 136e8a4c4f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33 ThomasK33 force-pushed the compaction-k3gj branch 2 times, most recently from 6b5cd3d to d979a7e Compare February 17, 2026 22:51
@ThomasK33
Copy link
Member Author

@codex review

Addressed P1: non-retryable errors now cancel pending retry timer via cancelPendingTimer(). Also fixed mock AI stream player's abort event to emit correct abortReason: "user" instead of reason: "user_cancelled", which fixes the streamInterrupt.test.ts test.

Added test coverage for the non-retryable-supersedes-retryable scenario.

@ThomasK33
Copy link
Member Author

@codex review

Addressed all 3 review comments:

  1. P1 - Compaction before persist: Moved on-send compaction check BEFORE persisting user message. When compaction triggers, the user message is NOT written to history (avoids duplication) — it becomes the follow-up sent after compaction completes.
  2. P2 - Emit retry-status clear: setEnabled(false) now emits auto-retry-abandoned when cancelling a pending retry (was already addressed in prior push, now confirmed in P1 fix too).
  3. P1 - Cancel timer on success: handleStreamSuccess() now calls cancelPendingTimer() to prevent stale timers from firing after recovery.

Also fixed mock AI stream player's abort event (abortReason: "user" instead of reason: "user_cancelled").

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc6bee46f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ethanndickson ethanndickson linked an issue Feb 18, 2026 that may be closed by this pull request
2 tasks
@ThomasK33
Copy link
Member Author

@codex review

Added a follow-up stabilization for CI parity:

  • WorkspaceStore.syncWorkspaces test now awaits one microtask before asserting onChat subscription call, matching async startup threshold sync timing.

Local validation still passes (make static-check).

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04d9feb6e4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed the two latest review threads:

  • clear stale transient auto-retry banner state on full replay reconnects;
  • seed on-send compaction usage from so usage never rehydrates from pre-compaction epochs.

Also added regression tests for both paths and reran Generated version.ts: v0.17.1-nightly.76-46-ge51161dc2 (e51161d) at 2026-02-19T07:46:17Z
Checking for PNG files in docs...
Running eslint...
ESLint checks passed!
[0] bun run node_modules/@typescript/native-preview/bin/tsgo.js --noEmit exited with code 0
[1] bun run node_modules/@typescript/native-preview/bin/tsgo.js --noEmit -p tsconfig.main.json exited with code 0
Checking TypeScript/JSON/Markdown formatting...
Checking formatting...
All matched files use Prettier code style!
Checking shell script formatting...
Checking Python formatting...
Nix not found; skipping Nix format check
✓ config/notifications.mdx is up-to-date with src/common/utils/tools/toolDefinitions.ts
✓ config/models.mdx is up-to-date with src/common/constants/knownModels.ts
✓ guides/github-actions.mdx is up-to-date with .github/workflows/auto-cleanup.yml
✓ agents/system-prompt.mdx is up-to-date with src/node/services/systemMessage.ts
✓ config/providers.mdx is up-to-date with src/node/utils/providerRequirements.ts
✓ workspaces/compaction/customization.mdx is up-to-date with src/node/builtinAgents/compact.md
✓ agents/agent-skills.mdx is up-to-date with .mux/skills/deep-review/SKILL.md
✓ workspaces/compaction/customization.mdx is up-to-date with src/common/constants/ui.ts
✓ agents/index.mdx is up-to-date with src/node/builtinAgents/*.md
✓ hooks/tools.mdx is up-to-date with src/common/utils/tools/toolDefinitions.ts
✓ src/node/services/agentSkills/builtInSkillContent.generated.ts is up-to-date
==> All formatting checks passed!
Checking for eager AI SDK imports in critical startup files...
✅ No eager AI SDK imports detected
Checking terminal-bench agent configuration...
Found agent CLI path: src/cli/run.ts
Verifying agent CLI startup (checking imports)...
✅ Agent CLI ran successfully
Terminal-bench agent check passed.

Checking npm package CLI completeness...

Checking CLI subcommand imports (bun, lockfile-free)...
✅ npm package CLI is complete (all subcommands boot under bun lockfile-free resolution)
🔗 Checking documentation links...
⠋ checking for broken links...
�[2K�[1A�[2K�[G⠙ checking for broken links...
�[2K�[1A�[2K�[G⠹ checking for broken links...
�[2K�[1A�[2K�[G⠸ checking for broken links...
�[2K�[1A�[2K�[G⠼ checking for broken links...
�[2K�[1A�[2K�[Gsuccess no broken links found
🔗 Checking code-to-docs links...
✅ All code-to-docs links valid
shellcheck --external-sources ./benchmarks/terminal_bench/mux-run.sh ./vscode/scripts/create-icon.sh ./tests/runtime/test-fixtures/ssh-server/entrypoint.sh ./scripts/lint.sh ./scripts/check_codex_comments.sh ./scripts/update_seti_icons.sh ./scripts/update_vercel_docs.sh ./scripts/wait_pr_codex.sh ./scripts/resolve_pr_comment.sh ./scripts/check_eager_imports.sh ./scripts/check-bench-agent.sh ./scripts/generate-version.sh ./scripts/pin-actions.sh ./scripts/wait_pr_checks.sh ./scripts/postinstall.sh ./scripts/wait_pr_ready.sh ./scripts/generate-npm-shrinkwrap.sh ./scripts/generate-builtin-agents.sh ./scripts/update_flake_hash.sh ./scripts/test.sh ./scripts/extract_pr_logs.sh ./scripts/familiarize.sh ./scripts/check_bundle_size.sh ./scripts/smoke-test.sh ./scripts/check-code-docs-links.sh ./scripts/generate-builtin-skills.sh ./scripts/setup-macos-signing.sh ./scripts/bump_tag.sh ./scripts/zizmor.sh ./scripts/check_pr_reviews.sh ./scripts/fmt.sh ./scripts/quick-cp-screenshot.sh
Nix not found; skipping flake hash check.

@ThomasK33
Copy link
Member Author

@codex review

Follow-up: previous comment had shell-escaped formatting issues. This push addresses both latest threads (full-replay retry-state reset + boundary-aware usage seeding) with regression tests and green static-check.

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. 👍

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e51161dc28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed the latest P1 in AskUserQuestionToolCall:

  • replaced unconditional useWorkspaceState(props.workspaceId ?? "") with a fail-soft subscription path that no-ops when workspaceId is absent and catches missing workspace lookups;
  • guarded downstream workspace-derived reads (autoRetryStatus / stream flags / last user message) for optional workspace context.

Validation: targeted browser/node tests + make static-check.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef78550273

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Follow-up fix for the latest P1:

  • preserved temporary auto-retry rollback state across workspace switches by tracking the workspace id that was temporarily enabled;
  • when the tool component context moves away from that workspace, it now immediately rolls back setAutoRetryEnabled(false) for the original workspace instead of dropping rollback refs;
  • rollback now uses the stored workspace id (not current props) so preference restoration remains correct.

Validation: targeted browser tests + make static-check.

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Bravo.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80d64f1f04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed latest P1 on on-send compaction semantics:

  • on-send compaction now triggers at usagePercentage >= thresholdPercentage (configured threshold),
    instead of requiring shouldForceCompact (threshold + force buffer);
  • retained shouldForceCompact semantics for mid-stream forcing only.

Added regression test coverage in agentSession.autoCompaction.test.ts for the 70-74% window.
Validation: targeted auto-compaction tests + make static-check.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f37a3d06aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed latest P1 in RetryBarrier manual retry flow:

  • temporary auto-retry enablement is now rolled back on both failure and success paths after resumeStream completes;
  • this restores previously-disabled user preference and avoids persisting unintended auto-retry enablement;
  • added regression test coverage for successful manual retry rollback.

Validation: RetryBarrier.test.tsx, agentSession.autoCompaction.test.ts, and make static-check.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9720b9214

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed latest P2 on teardown safety for temporary ask-user auto-retry enablement:

  • AskUserQuestionToolCall now performs teardown-safe rollback in an unmount cleanup effect when temporary rollback is still pending;
  • rollback callback now supports suppressed cleanup errors and uses a ref-backed API handle;
  • added a new component test (AskUserQuestionToolCall.test.tsx) that verifies unmount restores setAutoRetryEnabled(..., false) after a successful resume path.

Validation: new ask-user test + retry barrier test + auto-compaction test + make static-check.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96750fe692

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Addressed both latest P2 follow-ups:

  1. RetryBarrier manual retry rollback timing
  • deferred rollback until resumed stream/retry reaches a terminal state (after an observed in-flight phase),
  • kept immediate rollback on pre-stream resume failure,
  • added teardown/workspace-switch rollback safety,
  • added tests covering terminal-state rollback and unmount rollback.
  1. AskUserQuestionToolCall post-unmount arming race
  • added mount-state tracking and unmount-safe handling for temporary auto-retry enablement,
  • when enablement completes after unmount, we now immediately restore enabled: false instead of arming pending refs,
  • kept teardown cleanup rollback as fallback,
  • added a regression test that unmounts before async setup resolves.

Validation: targeted ask-user + retry-barrier + auto-compaction tests, and make static-check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move idle compaction request creation to backend

1 participant

Comments