SoloEngine v0.3.0 Release — Checkpoint Mechanism & Message Queue SoloEngine v0.3.0 introduces a checkpoint mechanism with three streaming checkpoints and a MessageQueue class for async message handling. The release also upgrades ModelManager to AutoComplete, refactors ReActCore for single-block responses, and improves error handling with SystemMessage type. 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