# SoloEngine v0.3.0 Release — Checkpoint Mechanism & Message Queue

> Source: <https://dev.to/sh4rlock/soloengine-v030-release-checkpoint-mechanism-message-queue-2i2l>
> Published: 2026-06-29 15:35:44+00:00

`ReActCore`

introduces three checkpoints during streaming: `content_ended`

(after text content), `before_tool_calls`

(before tool calls), and `after_tool_calls`

(after tool calls), enabling precise interception and state synchronization of the execution flow.`MessageQueue`

class in `run.py`

, supporting async enqueue, drain, and remove operations. Users can now queue messages while the LLM is running; queued messages are sent automatically after the current task completes. The frontend introduces a `QueueBar`

component to display queued messages, with CSS spinning animation, single-line ellipsis, and hover-to-delete functionality.`MessageQueue.drain_all()`

now merges consecutive messages with the same `name`

into a single message, preventing fragmented user input when multiple queue entries share the same sender.`message_queued`

, `queue_drained`

, and `queue_returned`

(`useRunWebSocket.ts`

). The frontend processes queue state updates in real time.`queue_returned`

. Checkpoint stops cleanly clear the queue and automatically start the next message.`SystemMessage`

type (with `notification`

role) to separate error messages from assistant content. Errors are now rendered as independent notification bubbles, no longer embedded within assistant message cards.`ReActCore`

initializes a `tiktoken`

encoder on startup for real-time token counting during streaming. Unknown models fall back to `o200k_base`

.`ModelManager`

has been upgraded from `Select`

to `AutoComplete`

, allowing users to type custom model names not in the predefined list.`ToolCallsBlock`

type (`message_block.py`

), unifying the internal tool-call format to an OpenAI-style `tool_calls`

list, replacing the legacy `ToolUseBlock`

.`_get_valid_token_value`

to uniformly handle `None`

/0/empty values from the API, preventing placeholder values from overwriting accumulated values.`react_core.py`

refactored: each `ChatResponse`

now contains only a single block type (`SoloTextBlock`

or `SoloThinkingBlock`

), replacing the previous pattern of accumulating multiple blocks before yielding. This enables the frontend to precisely handle each type of incremental content.`LLMMessage[]`

to `Message[]`

(`LLMMessage | SystemMessage`

). `convertToLLMMessages`

now splits system messages such as `error`

into independent `SystemMessage`

entries rather than reusing `LLMMessage`

. Updated `MessageList`

and `RunPanel`

to render `SystemMessage`

entries.`save_assistant_message`

now follow the same code path. `error`

is saved as an independent field and no longer written into the data block.`on_execution_done`

now detects empty-collector scenarios (where `stream_callback`

was never triggered) and automatically sets the status to `error`

with detailed LLM failure output. This prevents false "completed" status during silent failures.`createNewSession`

in `runPanelStore`

now immediately inserts the new session into the `sessions`

array, ensuring the UI reflects the new session without requiring a refresh.`isRunning`

or `isWaitingReply`

is true. The ENTER key now triggers send (queue) as long as the input has content, no longer blocked by `isRunning`

state.`execution_start`

now generates a new `msg_asst_${Date.now()}`

ID, preventing React key conflicts when the queue drain triggers a new assistant message that would otherwise duplicate the previous message ID.`websocket_handler.py`

has been significantly simplified, removing complex grace period and takeover logic. `RunContext`

now owns its own event loop, and the WebSocket only acts as a transport layer with injected callbacks.`aclose()`

closing the stream in `ReActCore`

no longer raises `CancelledError`

; it is treated as a normal end (breaking out of the loop), avoiding misinterpreting expected stream closure as a cancellation error.`ToolCallEventManager`

now uniformly sends tool-call events to the frontend through `tool_calls`

blocks, removing the legacy `tool_use`

block handling logic.`TruncatedFormatterBase`

removed `token_counter`

and `max_tokens`

parameters along with dead code such as `_truncate`

and `_count`

; the constructor is simplified to a no-arg empty implementation. `OpenAIChatFormatter`

removed the `OpenAIMultiAgentFormatter`

subclass.`anthropic_model.py`

captures `input_tokens`

in the `message_start`

event and accumulated `output_tokens`

in the `message_delta`

event, resolving inaccurate token counts in Anthropic streaming responses.`_convert_openai_to_anthropic_messages`

static method that converts OpenAI-format messages (`tool_calls`

, `reasoning_content`

) to Anthropic format (`tool_use`

, `thinking`

).`anthropic_model.py`

and `qwen_model.py`

now yield a separate `ChatResponse`

for each `tool_call`

, enabling precise handling on the frontend.`backend/SoloAgent/token_counter/`

directory, including `__init__.py`

, `openai_token_counter.py`

, and `token_base.py`

. The original functionality has been merged into `ReActCore`

inline accumulation.`backend/SoloAgent/formatter/truncated_formatter_base.py`

— removed from the exports in `__init__.py`

; the file is preserved but is no longer public API.`OpenAIMultiAgentFormatter`

from `openai_formatter.py`

.`ToolUseBlock`

— the message block type was unified from `tool_use`

to `tool_calls`

; the legacy `tool_use`

type is no longer used.`_convert_anthropic_message_to_solo_format`

function — removed a 99-line Anthropic→Solo format conversion function in `anthropic_model.py`

, replaced by the new OpenAI→Anthropic conversion method.`reasoning_content`

from content in `OpenAIChatFormatter`

, and removed the compatibility code (with DEBUG logs) that forcibly added an empty `reasoning_content`

to messages carrying `tool_calls`

.`TruncatedFormatterBase._group_messages`

now only checks `tool_calls`

and `tool_result`

types, removing `tool_use`

compatibility code.`agent.reply`

caught an exception and returned an error string, but `_execute_agent`

treated the run as `completed`

because the collector was empty. `on_execution_done`

now checks `collector.get_chunk_count() > 0`

and forces `status="error"`

with the actual LLM error output.`content`

blocks; they are rendered as independent `notification`

-role messages with proper styling and status indicators.`tool_use`

blocks in streaming responses, unifying to the `tool_calls`

format.`OpenAIChatFormatter`

adds filtering logic: when an assistant message has empty `content`

and no `tool_calls`

, it is skipped. This fixes the LLM API error "Input is a zero-length, empty document".`ChunkCollector._extract_raw_type`

in `run.py`

removed recognition of the `'tool_use'`

type string, unifying the mapping to `'tool_calls'`

.`aclose()`

closing the stream in `react_core.py`

no longer raises `CancelledError`

; it breaks out of the loop and is treated as a normal end, avoiding misinterpreting expected stream closure as a cancellation error.`aclose`

in `react_core.py`

, it is no longer converted to `asyncio.CancelledError`

; it breaks out of the loop and is treated as a normal end, avoiding misinterpreting expected stream closure as a cancellation error.`flow_compiler.py`

adds new logic: immediately after creating the flow, check whether `cancel_event`

is already set, and if so, cancel the flow right away, avoiding wasted HTTP connections.`flow_compiler.py`

fixed a bug where an interrupted Agent incorrectly returned `"completed"`

; it now returns `"stop"`

status. The `output`

field is no longer filled with `error`

, preventing error pollution of the output.`MessageList.tsx`

unifies on the W3C Clipboard API, ensuring that Windows clipboard history (Win+V) is correctly captured; fixed the issue where clipboard history could not be triggered on Windows.We're looking for like-minded contributors who share our passion for SoloEngine and Agentic AI. Every contribution — from a typo fix to a full feature — makes SoloEngine better.

📝 [Contributing Guide](https://github.com/Sh4r1ock/SoloEngine/blob/main/CONTRIBUTING.md) · 💬 [Discussions](https://github.com/Sh4r1ock/SoloEngine/discussions) · 📧 [Contact Us](mailto:sh4r1ock@qq.com)
