Originally published byDev.to
[v0.3.0] - 2026-06-29
🚀 Added
-
Checkpoint Mechanism —
ReActCoreintroduces three checkpoints during streaming:content_ended(after text content),before_tool_calls(before tool calls), andafter_tool_calls(after tool calls), enabling precise interception and state synchronization of the execution flow. -
Message Queue System — Added a new
MessageQueueclass inrun.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 aQueueBarcomponent to display queued messages, with CSS spinning animation, single-line ellipsis, and hover-to-delete functionality. -
Queue Message Merging —
MessageQueue.drain_all()now merges consecutive messages with the samenameinto a single message, preventing fragmented user input when multiple queue entries share the same sender. -
Queue WebSocket Events — The execution event protocol introduces three new event types:
message_queued,queue_drained, andqueue_returned(useRunWebSocket.ts). The frontend processes queue state updates in real time. -
Stop & Queue Integration — When the user clicks Stop, pending queued messages are returned to the input box via
queue_returned. Checkpoint stops cleanly clear the queue and automatically start the next message. -
System Notification Messages — Introduced the
SystemMessagetype (withnotificationrole) to separate error messages from assistant content. Errors are now rendered as independent notification bubbles, no longer embedded within assistant message cards. -
tiktoken Real-Time Token Estimation —
ReActCoreinitializes atiktokenencoder on startup for real-time token counting during streaming. Unknown models fall back too200k_base.
🔧 Improved
-
Custom Model Name Auto-Complete — The model name field in
ModelManagerhas been upgraded fromSelecttoAutoComplete, allowing users to type custom model names not in the predefined list. -
Message Block Type Unification — Added a new
ToolCallsBlocktype (message_block.py), unifying the internal tool-call format to an OpenAI-styletool_callslist, replacing the legacyToolUseBlock. -
ReActCore Token Accumulation — Token usage is now estimated chunk-by-chunk via tiktoken and overwritten with the API's precise usage when received. Introduced
_get_valid_token_valueto uniformly handleNone/0/empty values from the API, preventing placeholder values from overwriting accumulated values. -
ReActCore Streaming Architecture Refactor — Streaming output structure in
react_core.pyrefactored: eachChatResponsenow contains only a single block type (SoloTextBlockorSoloThinkingBlock), replacing the previous pattern of accumulating multiple blocks before yielding. This enables the frontend to precisely handle each type of incremental content. -
Message Type Separation — The frontend message type has been unified from
LLMMessage[]toMessage[](LLMMessage | SystemMessage).convertToLLMMessagesnow splits system messages such aserrorinto independentSystemMessageentries rather than reusingLLMMessage. UpdatedMessageListandRunPanelto renderSystemMessageentries. -
Unified Error Save Path — Normal and error paths in
save_assistant_messagenow follow the same code path.erroris saved as an independent field and no longer written into the data block. -
Execution Completion Reliability —
on_execution_donenow detects empty-collector scenarios (wherestream_callbackwas never triggered) and automatically sets the status toerrorwith detailed LLM failure output. This prevents false "completed" status during silent failures. -
Session Creation Flow —
createNewSessioninrunPanelStorenow immediately inserts the new session into thesessionsarray, ensuring the UI reflects the new session without requiring a refresh. -
Message Input UX — During LLM execution, the send button stays active to queue new messages instead of showing a blocking warning. The input area supports queuing via WebSocket when
isRunningorisWaitingReplyis true. The ENTER key now triggers send (queue) as long as the input has content, no longer blocked byisRunningstate. -
Assistant Message ID Uniqueness — Each
execution_startnow generates a newmsg_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 Architecture Refactor —
websocket_handler.pyhas been significantly simplified, removing complex grace period and takeover logic.RunContextnow owns its own event loop, and the WebSocket only acts as a transport layer with injected callbacks. -
Streaming Cancellation Handling — When the user clicks the stop button,
aclose()closing the stream inReActCoreno longer raisesCancelledError; it is treated as a normal end (breaking out of the loop), avoiding misinterpreting expected stream closure as a cancellation error. -
Tool Call Event Management —
ToolCallEventManagernow uniformly sends tool-call events to the frontend throughtool_callsblocks, removing the legacytool_useblock handling logic. -
Formatter Simplification —
TruncatedFormatterBaseremovedtoken_counterandmax_tokensparameters along with dead code such as_truncateand_count; the constructor is simplified to a no-arg empty implementation.OpenAIChatFormatterremoved theOpenAIMultiAgentFormattersubclass. -
Anthropic message_start/message_delta Usage Capture —
anthropic_model.pycapturesinput_tokensin themessage_startevent and accumulatedoutput_tokensin themessage_deltaevent, resolving inaccurate token counts in Anthropic streaming responses. -
Anthropic OpenAI Format Conversion — Added a new
_convert_openai_to_anthropic_messagesstatic method that converts OpenAI-format messages (tool_calls,reasoning_content) to Anthropic format (tool_use,thinking). -
Streaming Tool Call Split —
anthropic_model.pyandqwen_model.pynow yield a separateChatResponsefor eachtool_call, enabling precise handling on the frontend.
🗑️ Removed
- Removed the
backend/SoloAgent/token_counter/directory, including__init__.py,openai_token_counter.py, andtoken_base.py. The original functionality has been merged intoReActCoreinline 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. - Removed dead code
OpenAIMultiAgentFormatterfromopenai_formatter.py. -
ToolUseBlock— the message block type was unified fromtool_usetotool_calls; the legacytool_usetype is no longer used. -
_convert_anthropic_message_to_solo_formatfunction — removed a 99-line Anthropic→Solo format conversion function inanthropic_model.py, replaced by the new OpenAI→Anthropic conversion method. -
Reasoning_content injection code removed — Removed the logic that extracts
reasoning_contentfrom content inOpenAIChatFormatter, and removed the compatibility code (with DEBUG logs) that forcibly added an emptyreasoning_contentto messages carryingtool_calls. -
Message grouping removed tool_use support —
TruncatedFormatterBase._group_messagesnow only checkstool_callsandtool_resulttypes, removingtool_usecompatibility code.
🐛 Fixed
-
Empty Collector False Report — Fixed a bug where
agent.replycaught an exception and returned an error string, but_execute_agenttreated the run ascompletedbecause the collector was empty.on_execution_donenow checkscollector.get_chunk_count() > 0and forcesstatus="error"with the actual LLM error output. - LLM Tokens Missing on Manual Pause — Resolved via tiktoken real-time estimation, which serves as a fallback when API usage is unreachable.
-
Message Error Display — Error messages are no longer hidden inside assistant
contentblocks; they are rendered as independentnotification-role messages with proper styling and status indicators. -
Streaming tool_use Handling — Fixed the parsing and event-sending logic of legacy
tool_useblocks in streaming responses, unifying to thetool_callsformat. -
Filter Thinking-Only Messages in Cache —
OpenAIChatFormatteradds filtering logic: when an assistant message has emptycontentand notool_calls, it is skipped. This fixes the LLM API error "Input is a zero-length, empty document". -
ChunkCollector Type Mapping Correction —
ChunkCollector._extract_raw_typeinrun.pyremoved recognition of the'tool_use'type string, unifying the mapping to'tool_calls'. -
aclose No Longer Raises CancelledError —
aclose()closing the stream inreact_core.pyno longer raisesCancelledError; it breaks out of the loop and is treated as a normal end, avoiding misinterpreting expected stream closure as a cancellation error. -
model._was_cancelled Exception Conversion — When the model closes the stream due to
acloseinreact_core.py, it is no longer converted toasyncio.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 Early Cancellation Detection —
flow_compiler.pyadds new logic: immediately after creating the flow, check whethercancel_eventis already set, and if so, cancel the flow right away, avoiding wasted HTTP connections. -
CompiledFlow Interruption Detection —
flow_compiler.pyfixed a bug where an interrupted Agent incorrectly returned"completed"; it now returns"stop"status. Theoutputfield is no longer filled witherror, preventing error pollution of the output. -
Windows Clipboard Compatibility —
MessageList.tsxunifies 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.
🤝 Join Us
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 · 💬 Discussions · 📧 Contact Us
🇺🇸
More news from United StatesUnited States
NORTH AMERICA
Related News

Master Local Fine-Tuning with "gemma-trainer"
8h ago
Building a Plugin-Free Newsletter Popup on WordPress: Custom REST Endpoint Mailchimp API v3
8h ago
ภาษาโปรแกรมมิ่งที่ syntax ง่าย ทำให้ AI หลอนน้อยลง จริงหรือ?
8h ago
How I Built a File-Timestamp-Based Feedback Loop to Enforce AI Output Quality
8h ago
GitHub Trending Digest — 2026-07-07
9h ago