Long-Task Support
Long tasks aren’t about shrinking context — they’re about recoverable state. From Maka’s append-only log to Bubu’s interrupt recovery.
Bubu Agent’s design philosophy already dictates that it must be able to run 24h+ tasks, but model limitations mean it was always going to be a very complex engineering problem.
Early industry compression kept the first system prompt plus user message, trimmed the system prompts after that, and kept every later user input and model response. Later approaches used AI to summarize context. But either the compression was too weak or too much detail was lost — and these shortcomings are fatal in long-running work; production environments don’t allow that kind of risk.
Bubu kept looking for a long-task execution solution that could support real production, and eventually found the best fit for its needs in Maka.
Maka’s post Log Is the Runtime: Managing Agent State and Context with Append-Only Logs explains it very clearly, at https://github.com/apache/maka/blob/main/docs/blogs/log-is-the-runtime.md.
In short, Maka used several kinds of excellent systems thinking to design the agent. In Maka, a session is really several pages.
All records produced in a window are formatted and stored as logs in SQLite; Maka calls them logs. Each log body is one of several kinds of event content: Text, Thinking, FunctionCall, FunctionResponse, Error. Events also carry action fields such as stateDelta, permissionRequest, permissionDecision, tokenUsage, toolDispatch, toolRecovery, and endInvocation. The next model call reassembles from that; after the log is archived there is validation. A whole system was designed for this; the details are in Maka’s blog, and I won’t go into it here.
This excellent engineering thinking inspired Bubu, and Bubu designed a lightweight task interrupt/recovery system. Once a user request starts executing, Bubu marks the session with open_turn — the task boundary isn’t closed yet. A normal finish, a user stop, or an orderly app exit after flush clears the mark.
One thing to distinguish: when the user actively clicks stop, that isn’t this kind of clue. Stop closes the turn; it isn’t a crash, so it won’t auto-continue after a restart.
The message chain in SQLite is: user request, the model-issued tool call (T1), the tool result (T2). Tool execution is split into two observable states: T1 Dispatch means the model decided to call and the intent is durable; T2 Outcome means the result is durable and history is paired.
If a crash happens between the two, the system faces “side effects may already have happened, or they may not.” Here Bubu adopts the same conservative principle as Maka: when idempotence and safety can’t be proven, no silent redo; only what can be proven may silent-retry.
So the recovery strategy has two clear rules. Read-only tools, like reading files, searching, recalling memories, are simply silent-rerun on recovery, and the real result is written back into history. Environment-changing tools, like writing files, editing files, running commands, are not auto-redone; the system writes an explicit interrupt result — don’t assume success or failure; check the workspace first, then decide whether to retry — and the model continues reasoning with that fact.
After pairing unfinished tool calls, Bubu reopens the agent loop without new user input so the model continues the task from the restored prefix. When recovery starts, the UI shows a clear notice: unfinished task detected, auto-recovering; which steps were silent-retried; which write operations or commands are pending review. The user can dismiss the notice; the continuation itself is unaffected.