Skip to main content

Message Queue

PraisonAI CLI’s Interactive Mode supports message queuing, allowing you to type new prompts while the AI agent is still processing a previous task. Messages are queued and executed sequentially as each task completes. This feature is inspired by Claude Code, Windsurf Cascade, Cursor, and Gemini CLI.

Overview

The message queue system provides:
  • Non-blocking input - Type new messages while agent is processing
  • FIFO processing - Messages are processed in order (First In, First Out)
  • Visual indicators - See queue status and pending messages
  • Queue management - View, clear, or remove queued messages
  • Thread-safe - Safe concurrent access from multiple threads

Quick Start

# Start interactive mode
praisonai --interactive

# While the agent is processing, type more messages
# They will be queued and processed in order

How It Works

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                    Interactive Mode                              │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”    │
│  │ User Input  │───▶│ MessageQueue │───▶│ Agent Processing│    │
│  │             │    │   (FIFO)     │    │                 │    │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜    ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜    ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜    │
│         │                  │                     │              │
│         │                  ā–¼                     │              │
│         │          ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”              │              │
│         └─────────▶│ Queue Displayā”‚ā—€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜              │
│                    │  (visual UI) │                             │
│                    ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜                             │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
  1. User types a message - If agent is idle, it processes immediately
  2. Agent is busy - Message is added to the queue
  3. Agent completes - Next message in queue is automatically processed
  4. Queue is empty - Agent returns to idle state

Queue Commands

CommandDescription
/queueShow all queued messages
/queue clearClear the entire queue
/queue remove NRemove message at index N

Viewing the Queue

āÆ /queue

Queued Messages (3):
  0. ↳ Refactor the authentication module
  1. ↳ Add unit tests for the new feature
  2. ↳ Update the README with new instructions

Use /queue clear to clear, /queue remove N to remove

Clearing the Queue

āÆ /queue clear
āœ“ Cleared 3 queued message(s)

Removing a Specific Message

āÆ /queue remove 1
āœ“ Removed: Add unit tests for the new feature...

Live Status Display

While the agent is processing, a live status panel shows real-time updates:
āÆ Create a Python function to calculate fibonacci
╭──────────────────────────────────────╮
│ ā³ Calling LLM...                    │
│ šŸ“‹ Queued: 2                         │
╰──────────────────────────────────────╯
The status updates as the agent progresses:
  • ā³ Thinking... - Initial processing
  • ā³ Creating agent... - Setting up the agent
  • ā³ Calling LLM... - Making the API call

Visual Indicators

The queue system provides visual feedback:
IndicatorMeaning
ā³ Processing...Agent is currently processing a task
šŸ“‹ Queued (N)N messages are waiting in the queue
↳ messageA queued message (with truncation for long messages)
šŸ”§ tool_nameTool being executed
šŸ’» commandShell command being run

Processing States

The agent can be in one of three states:
StateDescription
IDLEReady to process new messages immediately
PROCESSINGCurrently working on a task
WAITING_APPROVALWaiting for user approval (e.g., file write)

Example Workflow

# Start interactive mode
praisonai --interactive

# Send first task
āÆ Create a Python function to calculate fibonacci numbers

# While agent is processing, queue more tasks
āÆ Add docstrings to the function
āÆ Create unit tests for edge cases
āÆ Write a README explaining usage

# Check the queue
āÆ /queue
ā³ Processing...
šŸ“‹ Queued (3)

Queued Messages (3):
  0. ↳ Add docstrings to the function
  1. ↳ Create unit tests for edge cases
  2. ↳ Write a README explaining usage

# Agent will process each task in order automatically

Programmatic Usage

You can also use the message queue programmatically:
from praisonai.cli.features.message_queue import (
    MessageQueue,
    StateManager,
    QueueDisplay,
    ProcessingState,
    MessageQueueHandler
)

# Create a queue
queue = MessageQueue()

# Add messages
queue.add("First task")
queue.add("Second task")
queue.add("Third task")

# Check queue status
print(f"Queue count: {queue.count}")  # 3
print(f"Is empty: {queue.is_empty}")  # False

# View all messages
messages = queue.get_all()
print(messages)  # ['First task', 'Second task', 'Third task']

# Pop first message (FIFO)
first = queue.pop()
print(first)  # 'First task'

# Peek without removing
next_msg = queue.peek()
print(next_msg)  # 'Second task'

# Remove at specific index
removed = queue.remove_at(1)
print(removed)  # 'Third task'

# Clear all
queue.clear()

Using the Handler

from praisonai.cli.features.message_queue import MessageQueueHandler, ProcessingState

# Create handler with a processor function
def my_processor(message):
    # Process the message (e.g., send to LLM)
    return f"Processed: {message}"

handler = MessageQueueHandler(processor=my_processor)

# Submit when idle - processes immediately
handler.submit("First task")

# Simulate processing state
handler.state_manager.set_state(ProcessingState.PROCESSING)

# Submit while processing - queued
handler.submit("Second task")
handler.submit("Third task")

# Check status
status = handler.get_status()
print(status)
# {'queue_count': 2, 'state': 'processing', 'messages': ['Second task', 'Third task']}

# When processing completes, call this to process queue
handler.on_processing_complete()

Visual Display

from praisonai.cli.features.message_queue import (
    MessageQueue, StateManager, QueueDisplay, ProcessingState
)

queue = MessageQueue()
queue.add("Task 1")
queue.add("Task 2")

state = StateManager()
state.set_state(ProcessingState.PROCESSING)

display = QueueDisplay(queue, state_manager=state)

# Format for display
print(display.format_status())      # ā³ Processing...
print(display.format_queue_count()) # šŸ“‹ Queued (2)
print(display.format_queue())       # ↳ Task 1\n↳ Task 2

API Reference

MessageQueue

MethodDescription
add(message)Add message to queue (returns False if empty)
pop()Remove and return first message (FIFO)
peek()View first message without removing
clear()Remove all messages
get_all()Get all messages as list
remove_at(index)Remove message at specific index
is_emptyProperty: True if queue is empty
countProperty: Number of messages in queue

StateManager

Method/PropertyDescription
current_stateGet current ProcessingState
is_idleTrue if state is IDLE
is_processingTrue if state is PROCESSING
set_state(state)Set new state (triggers callback)

QueueDisplay

MethodDescription
format_queue()Format queued messages with ↳ prefix
format_status()Format processing status indicator
format_queue_count()Format queue count indicator

MessageQueueHandler

MethodDescription
submit(message)Submit message (process or queue)
on_processing_complete()Called when processing finishes
get_status()Get queue count, state, messages
clear_queue()Clear all queued messages

Thread Safety

The message queue is thread-safe and uses threading.Lock for all operations. This ensures safe concurrent access when:
  • User input thread adds messages
  • Processing thread pops messages
  • Display thread reads queue status

Performance

The message queue is designed for minimal performance impact:
  • Lazy loading - Module only loaded when interactive mode starts
  • Simple data structure - Python list with O(1) append, O(n) pop(0)
  • No external dependencies - Uses only Python standard library
  • Minimal memory - Stores only message strings

Comparison with Other Tools

FeaturePraisonAIClaude CodeWindsurfCursor
Queue messagesāœ…āœ…āœ…āœ…
View queueāœ… /queueāœ…āœ…āœ…
Clear queueāœ… /queue clearāœ…āœ… Deleteāœ…
Remove specificāœ… /queue remove NāŒāœ… DeleteāŒ
Visual indicatorsāœ…āœ…āœ…āœ…
FIFO processingāœ…āœ…āœ…āœ…

Async Processing Classes

The message queue includes additional classes for async processing:

AsyncProcessor

Runs work functions in background threads:
from praisonai.cli.features.message_queue import AsyncProcessor

processor = AsyncProcessor()

def on_complete(result):
    print(f"Done: {result}")

def on_status(status):
    print(f"Status: {status}")

# Start background processing
processor.start(
    work_fn=lambda: "result",
    on_complete=on_complete,
    on_status=on_status
)

# Check if running
print(processor.is_running)  # True/False

LiveStatusDisplay

Tracks and displays real-time status:
from praisonai.cli.features.message_queue import LiveStatusDisplay

display = LiveStatusDisplay()

# Update status
display.update_status("Thinking...")
display.update_status("Calling LLM...")

# Track tool calls
display.add_tool_call("read_file", {"path": "main.py"})
display.add_command_execution("ls -la")

# Get formatted status
print(display.format_live_status())
# ā³ Calling LLM...
# šŸ”§ read_file
# šŸ’» ls -la

# Clear when done
display.clear()

NonBlockingInput

Manages async user input:
from praisonai.cli.features.message_queue import NonBlockingInput

input_handler = NonBlockingInput()

# Submit input (from another thread)
input_handler.submit("user message")

# Check for pending input
if input_handler.has_input():
    msg = input_handler.get_input()
    print(f"Got: {msg}")