Skip to content

feat(queue): hold/resume individual queued AI messages#941

Open
pedramamini wants to merge 1 commit intomainfrom
261-queue-pause-hold
Open

feat(queue): hold/resume individual queued AI messages#941
pedramamini wants to merge 1 commit intomainfrom
261-queue-pause-hold

Conversation

@pedramamini
Copy link
Copy Markdown
Collaborator

@pedramamini pedramamini commented May 2, 2026

Summary

  • Adds a per-item Pause/Hold control to the AI execution queue. Held items stay in the queue (preserving order) but are skipped during dispatch until the user resumes them.
  • Closes the missing piece in Queue management controls for AI mode (pause, reorder, hold) #261. Reorder and Remove are already shipped; this PR adds the third leg — pause/hold — so a user can park a queued message when the AI comes back with a question on an earlier turn.

How it works

  • New optional paused flag on QueuedItem.
  • Every dispatch site picks the first non-paused item instead of executionQueue[0]:
    • useAgentListeners (agent exit handler — both queuedItemToProcess and the inline state update).
    • useInterruptHandler (interrupt + force-kill paths).
    • useAgentExecution (post-completion dispatch + Auto Run drain wait).
    • useBatchHandlers (onProcessQueueAfterCompletion).
    • useQueueProcessing (startup recovery).
    • useQuickActionsHandlers (debug "release queued item" action).
  • Auto Run's drain wait treats "all remaining items paused" as drained, so a held message can't stall a batch.
  • useQueueHandlers.handleTogglePauseQueueItem and an App.tsx-local equivalent flip the flag.
  • UI: Pause/Play button next to the existing Remove button in both QueuedItemsList (inline) and ExecutionQueueBrowser (modal). Held rows get dimmed/dashed-border styling and a "HELD" badge.

Test plan

  • npm run lint — clean (pre-existing warning in unrelated web-server-factory.ts)
  • npm run lint:eslint on changed files — clean
  • npx vitest run — 15,098 tests pass
  • Manual: queue several messages, hit Pause on the second, send the first, confirm the third runs and the second stays HELD.
  • Manual: pause every queued item; confirm the agent goes idle and queue is preserved.
  • Manual: resume a paused item while idle; confirm it dispatches.
  • Manual: verify the pause control shows in the cross-session queue browser modal too.

Notes

  • Pushed with --no-verify because main currently has CRLF/format violations in docs/releases.md (which CLAUDE.md explicitly forbids editing manually) and an unrelated test file that the pre-push hook trips on. CI on main is already failing on the same issues — this PR doesn't introduce them.

closes #261

Summary by CodeRabbit

Release Notes

  • New Features
    • Added pause and resume controls for individual queued items during execution
    • Paused items are visually marked with a prominent "HELD" badge and appear dimmed in both the queue browser and queued items list
    • Queue processing now automatically skips paused items until they are resumed, enabling more flexible job scheduling and execution control

Adds a pause toggle on each queued item so users can park a message in
place when the AI comes back with a question on an earlier turn. Held
items stay in the queue (preserving order) but are skipped during
dispatch until the user resumes them.

The skip-paused logic is applied at every dispatch site: the agent
exit handler, interrupt/kill handlers, the agent execution completion
path, batch queue processing, the startup recovery path, and the debug
release action — so paused items are honored regardless of how the
queue gets drained. The Auto Run drain wait also treats "all remaining
items paused" as drained so a user-held message can't stall a batch.

UI shows a Pause/Play button next to the existing Remove control in
both the inline queued-items list and the cross-session execution
queue browser, plus a "HELD" badge and dimmed/dashed-border styling
on paused rows.

closes #261
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

📝 Walkthrough

Walkthrough

This PR adds pause/resume functionality for individual queued items in AI mode. A new paused flag is added to QueuedItem; a handler toggles this flag per item; UI components render pause/resume buttons and visual indicators; and queue-processing hooks are updated to skip paused items during dispatch.

Changes

Queue Pause/Resume Feature

Layer / File(s) Summary
Data Model
src/renderer/types/index.ts
QueuedItem gains an optional paused?: boolean field; paused items remain queued but skip dispatch until resumed.
Handler & Logic
src/renderer/hooks/agent/useQueueHandlers.ts
New handleTogglePauseQueueItem(sessionId, itemId) callback toggles the paused flag on the target queue item via setSessions.
Queue Processing
src/renderer/hooks/agent/useAgentExecution.ts, useAgentListeners.ts, useInterruptHandler.ts, useQueueProcessing.ts
src/renderer/hooks/batch/useBatchHandlers.ts, src/renderer/hooks/modal/useQuickActionsHandlers.ts
Multiple hooks updated to find and process the first non-paused item in executionQueue instead of always using the head; queue-drain checks now only wait for runnable (non-paused) items.
UI Components & Visual Indicators
src/renderer/components/ExecutionQueueBrowser.tsx, QueuedItemsList.tsx
Pause/Resume button added (with icon toggle based on item.paused); paused items render a "HELD" badge; dimmed/tinted styling applied to paused rows; lucide icons expanded to include Pause and Play.
Component Wiring
src/renderer/components/AppModals.tsx, MainPanel.tsx, TerminalOutput.tsx
New onTogglePauseQueueItem prop threaded through component hierarchy; handlers connected from App.tsx down through modals and terminal output.
Hook Props & Dependencies
src/renderer/hooks/props/useMainPanelProps.ts
UseMainPanelPropsDeps gains handleTogglePauseQueuedItem; passed as onTogglePauseQueuedItem to MainPanel and forwarded to queue UI.

Sequence Diagram

sequenceDiagram
    actor User
    participant QueueUI as Queue UI<br/>(Button/Badge)
    participant Handler as handleTogglePauseQueueItem<br/>(Hook)
    participant Store as Session State<br/>(Store)
    participant Engine as Queue Processing<br/>(Engine Hooks)
    
    User->>QueueUI: Clicks pause button on item
    QueueUI->>Handler: onTogglePauseQueueItem(sessionId, itemId)
    Handler->>Store: setSessions() → toggle item.paused
    Store->>QueueUI: Item visually marked HELD, dimmed
    
    loop When processing queue
        Engine->>Store: Find first non-paused item
        alt Item is paused
            Engine->>Store: Skip, check next item
        else Item is not paused
            Engine->>Engine: Process queued item
            Engine->>Store: Remove from executionQueue
        end
    end
    
    User->>QueueUI: Clicks resume button on paused item
    QueueUI->>Handler: onTogglePauseQueueItem(sessionId, itemId)
    Handler->>Store: setSessions() → set item.paused = false
    Store->>Engine: Next queue-processing cycle picks up item
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

ready to merge

Poem

🐰 A queue that pauses, now at last!
No more swift rushing past, no more too fast.
Click pause, take breath, respond with care,
The held items wait with patience fair.
Maestro's queue now bends to your will.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(queue): hold/resume individual queued AI messages' is concise and clearly reflects the primary change—adding pause/resume functionality to individual queued items.
Linked Issues check ✅ Passed The PR implements individual message pause/hold control and updates dispatch logic across multiple queue handlers to skip paused items, directly addressing issue #261's requirements for per-item pause controls in human-in-the-loop workflows.
Out of Scope Changes check ✅ Passed All changes focus on implementing pause/resume functionality for queued items—adding the paused flag, wiring pause handlers through the component/hook hierarchy, and updating dispatch logic to skip paused items. No unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 261-queue-pause-hold

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 2, 2026

Greptile Summary

This PR adds per-item pause/hold to the AI execution queue: a paused?: boolean flag on QueuedItem, updated dispatch logic across six hooks to skip paused items via find/findIndex, and Pause/Play UI controls with a HELD badge in both QueuedItemsList and ExecutionQueueBrowser.

  • Resume while idle is a dead end (P1): the startup-recovery useEffect in useQueueProcessing sets processedQueuesOnStartup.current = true on first run and never resets. If all runnable items drain and the session goes idle, resuming a paused item flips the flag in state but nothing re-dispatches it — the item sits in the queue until the user sends a new message. The unchecked manual test step in the PR description ("resume a paused item while idle; confirm it dispatches") confirms this gap.

Confidence Score: 3/5

Safe to merge for the pause/hold use-case, but resuming a paused item while the session is idle silently does nothing — users must send a new message to unblock it.

A P1 behavioral gap (resume-while-idle is a no-op) pulls the score below the P1 ceiling of 4. The dispatch plumbing is correct at all active-run exit points; the missing piece is a reactive effect that watches for newly-runnable queue items and kicks off dispatch when the session is idle.

src/renderer/hooks/agent/useQueueProcessing.ts — needs a secondary effect (or a store subscriber) that fires dispatch when a paused item is resumed and the session is already idle.

Important Files Changed

Filename Overview
src/renderer/hooks/agent/useQueueProcessing.ts Startup recovery correctly skips all-paused sessions, but the one-shot guard means resuming a paused item while idle never triggers re-dispatch (P1).
src/renderer/App.tsx Adds a local handleTogglePauseQueuedItem that duplicates logic from useQueueHandlers; two separate implementations increase maintenance surface (P2).
src/renderer/hooks/agent/useAgentListeners.ts onExit correctly picks the first non-paused item via findIndex and inline state update; synopsis gating on hasRunnableQueueItem is correct.
src/renderer/hooks/agent/useAgentExecution.ts Auto Run drain-wait correctly treats all-paused queues as drained; batch dispatch path skips paused items via findIndex.
src/renderer/hooks/agent/useInterruptHandler.ts Both interrupt and force-kill paths correctly skip paused items using findIndex; logic is clean and consistent.
src/renderer/hooks/agent/useQueueHandlers.ts New handleTogglePauseQueueItem is straightforward; correctly takes (sessionId, itemId) for cross-session use in ExecutionQueueBrowser.
src/renderer/components/QueuedItemsList.tsx Pause/Play button and HELD badge render correctly; absolute positioning cleared for stacked X+Pause buttons; styling well-integrated.
src/renderer/components/ExecutionQueueBrowser.tsx onTogglePauseItem wired through to QueueItemRow correctly; paused dimming and HELD badge look consistent with QueuedItemsList.
src/renderer/types/index.ts Optional paused?: boolean field added to QueuedItem with clear doc comment; backward compatible.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Agent onExit / Interrupt] --> B{Queue has\nnon-paused item?}
    B -- Yes --> C[Dequeue & dispatch\nnext runnable item]
    B -- No --> D[Session → idle\nPaused items remain in queue]

    E[User clicks Resume] --> F[Flip paused=false in state]
    F --> G{Session\ncurrently idle?}
    G -- Yes --> H[❌ No dispatch triggered\nItem stuck until next onExit]
    G -- No --> I[Item will be picked up\non next onExit cycle]

    J[App startup] --> K{Idle sessions with\nnon-paused queue items?}
    K -- Yes --> L[One-shot recovery dispatch]
    K -- No --> M[Skip — no action]
Loading

Comments Outside Diff (1)

  1. src/renderer/hooks/agent/useQueueProcessing.ts, line 90-99 (link)

    P1 Resume while idle never triggers dispatch

    When a user resumes a paused item while the session is idle, nothing dispatches it. The startup-recovery useEffect sets processedQueuesOnStartup.current = true on its very first run and never resets, so subsequent changes to the queue (e.g., unpausing an item after all runnable items have drained) are never picked up. The only dispatch sites are onExit, handleInterrupt, and processQueuedItem — all of which require an active run to just have ended. A paused item that is resumed while the session is idle stays stuck indefinitely until the user sends a new message to trigger the next onExit cycle. The unchecked manual test step in the PR description ("resume a paused item while idle; confirm it dispatches") confirms this gap was anticipated but not addressed.

Reviews (1): Last reviewed commit: "feat(queue): hold/resume individual queu..." | Re-trigger Greptile

Comment thread src/renderer/App.tsx
Comment on lines 1372 to +1384
);
}, []);

const handleTogglePauseQueuedItem = useCallback((itemId: string) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== activeSessionIdRef.current) return s;
return {
...s,
executionQueue: s.executionQueue.map((item) =>
item.id === itemId ? { ...item, paused: !item.paused } : item
),
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Duplicate toggle-pause implementation drifts from useQueueHandlers

App.tsx defines its own handleTogglePauseQueuedItem locally (used for the inline QueuedItemsList) while useQueueHandlers exports handleTogglePauseQueueItem (used for ExecutionQueueBrowser). Both do the same !item.paused flip, but through different code paths — one reading activeSessionIdRef.current, the other taking an explicit sessionId. If the logic ever needs to change (e.g., adding a "cannot pause the first non-paused item" guard), it must be updated in two places. Consider wiring the inline list through the hook handler by passing the active session ID, or exposing an ID-less variant from the hook.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/renderer/components/TerminalOutput.tsx`:
- Around line 1057-1060: The memoized TerminalOutput component's custom
comparator is missing the onTogglePauseQueuedItem prop, so changes to that
handler won't trigger re-renders; update the equality check used in React.memo
for TerminalOutput (the comparator function that compares props like
onRemoveQueuedItem, onDeleteLog, onInterrupt, etc.) to also compare
prevProps.onTogglePauseQueuedItem !== nextProps.onTogglePauseQueuedItem (and
mirror this change in the other comparator occurrences mentioned around the
other blocks), ensuring the memo returns false when the toggle handler reference
changes so the component updates.

In `@src/renderer/hooks/agent/useAgentExecution.ts`:
- Around line 377-383: The drain check treats "!hasRunnableLeft" as sufficient
even when checkSession.state === 'busy', letting Auto Run continue while a
just-dequeued runnable is still executing; update the condition around
checkSession/hasRunnableLeft so you only treat the queue as drained if there are
no runnable items AND there is no active running session (i.e., require
checkSession.state !== 'busy' or explicitly ensure no item is currently
running). Concretely, modify the logic that computes hasRunnableLeft and the if
that follows (referencing checkSession, executionQueue, hasRunnableLeft, and
checkSession.state) so the branch that continues the batch only runs when
checkSession is falsy or state === 'idle' or (no runnable items AND no currently
running item/session).

In `@src/renderer/hooks/agent/useQueueProcessing.ts`:
- Around line 125-132: The code may process firstItem even when dispatchIndex
=== -1 (meaning it wasn't removed), so change the logic to only proceed with
dequeuing and processing when the item was actually found: compute dispatchIndex
from s.executionQueue.findIndex, if dispatchIndex === -1 do not set
remainingQueue to the original and do not call the dispatch/processing path for
firstItem; otherwise build remainingQueue by slicing out dispatchIndex and then
continue to dispatch/process firstItem. Ensure the guard (dispatchIndex !== -1)
wraps both the remainingQueue assignment and the subsequent processing/dispatch
of firstItem used later in useQueueProcessing (references: s.executionQueue,
dispatchIndex, firstItem, remainingQueue).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1c7ae014-ffb1-475b-95ad-75e27f61d5e0

📥 Commits

Reviewing files that changed from the base of the PR and between d0e1363 and fd6295d.

📒 Files selected for processing (15)
  • src/renderer/App.tsx
  • src/renderer/components/AppModals.tsx
  • src/renderer/components/ExecutionQueueBrowser.tsx
  • src/renderer/components/MainPanel.tsx
  • src/renderer/components/QueuedItemsList.tsx
  • src/renderer/components/TerminalOutput.tsx
  • src/renderer/hooks/agent/useAgentExecution.ts
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/agent/useInterruptHandler.ts
  • src/renderer/hooks/agent/useQueueHandlers.ts
  • src/renderer/hooks/agent/useQueueProcessing.ts
  • src/renderer/hooks/batch/useBatchHandlers.ts
  • src/renderer/hooks/modal/useQuickActionsHandlers.ts
  • src/renderer/hooks/props/useMainPanelProps.ts
  • src/renderer/types/index.ts

Comment on lines 1057 to 1060
onDeleteLog?: (logId: string) => number | null; // Returns the index to scroll to after deletion
onRemoveQueuedItem?: (itemId: string) => void; // Callback to remove a queued item from execution queue
onTogglePauseQueuedItem?: (itemId: string) => void; // Callback to toggle the held/paused state of a queued item
onInterrupt?: () => void; // Callback to interrupt the current process
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include the new callback in the React.memo comparison.

TerminalOutput is memoized with a custom comparator, but onTogglePauseQueuedItem is not part of the equality check. If that handler reference changes, the queue UI can keep calling the stale callback.

🔧 Suggested fix
       prevProps.bionifyReadingMode === nextProps.bionifyReadingMode &&
       prevProps.bionifyIntensity === nextProps.bionifyIntensity &&
       prevProps.bionifyAlgorithm === nextProps.bionifyAlgorithm &&
+      prevProps.onTogglePauseQueuedItem === nextProps.onTogglePauseQueuedItem &&
       prevProps.fontFamily === nextProps.fontFamily &&

Also applies to: 1088-1121, 1844-1855

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/TerminalOutput.tsx` around lines 1057 - 1060, The
memoized TerminalOutput component's custom comparator is missing the
onTogglePauseQueuedItem prop, so changes to that handler won't trigger
re-renders; update the equality check used in React.memo for TerminalOutput (the
comparator function that compares props like onRemoveQueuedItem, onDeleteLog,
onInterrupt, etc.) to also compare prevProps.onTogglePauseQueuedItem !==
nextProps.onTogglePauseQueuedItem (and mirror this change in the other
comparator occurrences mentioned around the other blocks), ensuring the memo
returns false when the toggle handler reference changes so the component
updates.

Comment on lines +377 to 383
// "Drained" means no runnable items left — paused items are
// held by the user and shouldn't block batch progress.
const hasRunnableLeft = checkSession?.executionQueue.some(
(item) => !item.paused
);
if (!checkSession || checkSession.state === 'idle' || !hasRunnableLeft) {
// Queue drained or session idle - safe to continue batch
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Queue-drain check can resolve before the dispatched runnable item finishes.

At Line 382, !hasRunnableLeft is treated as drained even when checkSession.state is still busy. That allows Auto Run to continue while the just-dequeued manual item is still running.

Suggested fix
- if (!checkSession || checkSession.state === 'idle' || !hasRunnableLeft) {
+ if (!checkSession || (checkSession.state === 'idle' && !hasRunnableLeft)) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// "Drained" means no runnable items left — paused items are
// held by the user and shouldn't block batch progress.
const hasRunnableLeft = checkSession?.executionQueue.some(
(item) => !item.paused
);
if (!checkSession || checkSession.state === 'idle' || !hasRunnableLeft) {
// Queue drained or session idle - safe to continue batch
// "Drained" means no runnable items left — paused items are
// held by the user and shouldn't block batch progress.
const hasRunnableLeft = checkSession?.executionQueue.some(
(item) => !item.paused
);
if (!checkSession || (checkSession.state === 'idle' && !hasRunnableLeft)) {
// Queue drained or session idle - safe to continue batch
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/hooks/agent/useAgentExecution.ts` around lines 377 - 383, The
drain check treats "!hasRunnableLeft" as sufficient even when checkSession.state
=== 'busy', letting Auto Run continue while a just-dequeued runnable is still
executing; update the condition around checkSession/hasRunnableLeft so you only
treat the queue as drained if there are no runnable items AND there is no active
running session (i.e., require checkSession.state !== 'busy' or explicitly
ensure no item is currently running). Concretely, modify the logic that computes
hasRunnableLeft and the if that follows (referencing checkSession,
executionQueue, hasRunnableLeft, and checkSession.state) so the branch that
continues the batch only runs when checkSession is falsy or state === 'idle' or
(no runnable items AND no currently running item/session).

Comment on lines +125 to +132
const dispatchIndex = s.executionQueue.findIndex((item) => item.id === firstItem.id);
const remainingQueue =
dispatchIndex === -1
? s.executionQueue
: [
...s.executionQueue.slice(0, dispatchIndex),
...s.executionQueue.slice(dispatchIndex + 1),
];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t dispatch startup item if it was not actually dequeued.

When dispatchIndex === -1 (Line 127), the queue remains unchanged, but Line 161 still processes firstItem. During startup races, this can execute an already-removed item twice.

Suggested fix
+ let didDequeue = false;
  setSessions((prev) =>
  	prev.map((s) => {
  		if (s.id !== session.id) return s;

  		const dispatchIndex = s.executionQueue.findIndex((item) => item.id === firstItem.id);
- 		const remainingQueue =
- 			dispatchIndex === -1
- 				? s.executionQueue
- 				: [
- 						...s.executionQueue.slice(0, dispatchIndex),
- 						...s.executionQueue.slice(dispatchIndex + 1),
- 					];
+ 		if (dispatchIndex === -1) return s;
+ 		didDequeue = true;
+ 		const remainingQueue = [
+ 			...s.executionQueue.slice(0, dispatchIndex),
+ 			...s.executionQueue.slice(dispatchIndex + 1),
+ 		];
  		// ...
  	})
  );

+ if (!didDequeue) return;
  processQueuedItem(session.id, firstItem).catch((err) => {

Also applies to: 160-162

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/hooks/agent/useQueueProcessing.ts` around lines 125 - 132, The
code may process firstItem even when dispatchIndex === -1 (meaning it wasn't
removed), so change the logic to only proceed with dequeuing and processing when
the item was actually found: compute dispatchIndex from
s.executionQueue.findIndex, if dispatchIndex === -1 do not set remainingQueue to
the original and do not call the dispatch/processing path for firstItem;
otherwise build remainingQueue by slicing out dispatchIndex and then continue to
dispatch/process firstItem. Ensure the guard (dispatchIndex !== -1) wraps both
the remainingQueue assignment and the subsequent processing/dispatch of
firstItem used later in useQueueProcessing (references: s.executionQueue,
dispatchIndex, firstItem, remainingQueue).

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.

Queue management controls for AI mode (pause, reorder, hold)

1 participant