Writing

State and recovery in long-running agents

Model inference happens inside a call, but real work unfolds over time. A reliable agent must pause, recover, remain visible, and turn completion into delivery.

After building Oracle, we quickly ran into a question more fundamental than how to make an agent do more: how long should its work remain alive?

A model call may take seconds, and a network request must eventually end. Real tasks do not obey that timescale. Research may wait for new material. Generation may take a long time. A user may leave the page and return later with a different requirement. When an agent’s lifecycle is bound to a request, it can produce an impressive demonstration without becoming a dependable product.

We came to see the request as the beginning of the work, not the container for it.

A request can end while the work continues

Traditional software often treats an interaction as a complete transaction: receive input, execute logic, and return a result. For short, deterministic operations, that structure is simple and effective.

An agent, however, works toward an open-ended goal. It may require several rounds of judgment, multiple tools, and material that changes along the way. The longer it runs, the less likely it is that a page, a connection, or a single computation will remain available throughout. If everything must finish inside one request, waiting becomes a timeout, leaving looks like an interruption, and recovery means starting over.

That is not a performance problem. It is a lifecycle designed around the wrong unit.

A better relationship is for a request to create or advance a piece of work whose state exists independently. The user can leave, the interface can close, and a step can become temporarily blocked without erasing what the task has already accomplished.

Paused is a valid state

Our first instinct was to divide tasks into two states: running and complete. We later found that the most important parts of real work often live between them.

An agent may be waiting for a user to choose, waiting for an external result, or discovering that it needs another condition before acting. None of these situations is necessarily a failure. Knowing when not to continue is part of the system’s judgment.

Pausing therefore cannot mean merely stopping a process. The system must preserve completed actions, unresolved questions, and the context required to continue. When the user returns, the agent should resume from a meaningful boundary rather than replaying the entire process.

I began to understand pause as a product capability. It lets a person enter the agent’s work, change its direction, and return control to the system.

Recovery matters more than retry

Trying again after failure sounds reasonable. In long-running work, blind retries often create more problems.

A step may have succeeded even though its response was lost. An artifact may already exist, so repeating the action creates a duplicate. A task may also be advanced by two state changes at nearly the same time. If the system cannot determine what happened before, it cannot know whether to retry, skip, or wait.

Reliability is therefore not simply the willingness to try again. It is the ability to continue correctly under uncertainty. The system must distinguish completed facts, unconfirmed outcomes, and the next action that remains safe.

The model can decide what to do next, but it should not carry the full burden of remembering execution history. Recovery comes from outside the model: explicit state, stable boundaries, and a runtime that treats repeated action with care.

Progress must become product language

Continuing in the background does not mean that a user will believe the work is still alive.

When progress exists only in logs, the user sees an interface that has stopped changing. They cannot tell whether the task is advancing, waiting, failing, or already partially complete. A system may have rich internal state and still remain a black box to the person relying on it.

We began treating progress as part of the agent product rather than debugging information. Users do not need every internal step, but they should understand what is happening: what the task is working on, why it stopped, whether they need to act, and which results are already usable.

Notifications should serve those meaningful transitions. The fact that the system executed one more step is rarely worth an interruption. Completion, a required decision, or a result that can now be used often is.

Completion is not delivery

Long-running tasks also exposed another distinction that is easy to miss: the system finishing execution does not mean the user has received a result.

An agent may create many intermediate artifacts. They help later decisions, but they are not necessarily what the user ultimately needs. If the product presents every file at the same level, the user must still decide which items are drafts, which are working material, and which are outcomes worth taking away.

A deliverable must therefore be an explicit product concept. The system needs to know not only whether a step ended, but what role its result plays, whether it is complete enough, and how it should return to the user.

This turns completion from a runtime state into a user outcome. The agent’s responsibility should not end when computation stops. It should extend until the work is visible, understandable, and ready to be used again.

Reliability is a structure of collaboration

During this period, the team was advancing Oracle across the interface, task execution, and background coordination at the same time. The pause, recovery, notification, repeated-execution, and delivery problems we encountered did not belong to one isolated module.

Together they showed that agent reliability cannot be created by a stronger model, a longer queue, or a more elaborate status field alone. It depends on whether the parts of the product share the same definition of the work.

The runtime must know whether a task can continue. The product must help the user understand where it is. The delivery layer must know which results actually belong to the user. If any layer still treats the agent as a request, the experience breaks at that boundary.

Work unfolds over time

What most distinguishes an agent from a conventional generative feature may not be the number of tools it can call. It is the responsibility it begins to assume across time.

When a user starts a task, they are entering a continuing agreement with the product: the system will not forget because a page closes, erase completed work because one step fails, or disguise a pile of intermediate material as a finished result.

Model inference happens in moments. Work unfolds over time.

A reliable agent system must make it possible for the former to remain coherent throughout the latter.

Article activity

readscomments

Discussion

Comments

Questions, disagreements, and useful additions are all welcome.

Leave a comment

Comments publish immediately and can be deleted from this browser.

A privacy-friendly human check runs when you publish.