[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
Top comments (0)