Research

Building Long-Horizon Agents

We present a method for building long-horizon agents that work continuously over time, schedule their own activities, and create workflows dynamically. Unlike traditional agents that only respond to user input, long-horizon agents actively pursue goals without constant prompting. This describes the architecture, memory systems, and operational patterns that enable sustained autonomous behavior.

Orin LabsMay 2025

Key Takeaways

  • Self-scheduling: the agent decides when to wake, cutting idle compute.
  • Wake events: external signals wake the agent immediately for urgent work.
  • Layered memory: long-horizon summaries keep context without linear growth.
  • Durable state in tools: facts live in calendars/contacts, not chat tokens.
  • Constraint: ledger-style memory implies single-threaded execution per agent.

1.Introduction

Many implementations of AI agents have a fundamental problem: they only work when prompted. These systems act like reactive utilities—they wait for input, process it through predefined steps, then go idle. This event-driven design creates a hard boundary that prevents sustained, autonomous operation.

Applications (like teaching) that require long-term engagement, planning, and management reveal how inadequate purely reactive agents are. Instead, we propose agents that exist independently from their user or input events.

This work presents a fundamental redesign of how agents operate. We introduce the long-horizon agent: an agent that schedules its own activities, reasons about time, and creates dynamic workflows on the fly. These systems maintain persistent awareness of context while adapting their behavior to align with changing objectives.


2.Limitations of Reactive Architectures

The standard reactive agent architecture follows a simple, deterministic pattern:

python
input event → LLM → workflows → output

This single-pass model breaks down when there's no external input. Without external input, the architecture has no way to take initiative. Below are iterative examples of how existing architectures attempt to fix this problem:

2.1User-Triggered Static Workflows

The naive approach: basic workflows that only run when users click buttons. These systems have zero autonomous initiative and lose all context between sessions.

python
def on_button_pressed(...):
    foo = workflow_part_1(...)
    bar = workflow_part_2(foo)
    baz = workflow_part_3(bar)
    return baz

2.2Beat-Scheduled Static Workflows

Static workflows that run on fixed schedules (like cron jobs). This approach is still limited to a fixed set of static workflows, wastes resources by constantly checking for work, and still follows rigid, predetermined patterns.

python
def run_every_hour(...): # runs 0 * * * *
    lessons = get_upcoming_lessons() # in next hour
    for lesson in lessons:
        lesson.plan() # another LLM call to plan the lesson

2.3Beat-Schedule + LLM-Selected Workflows

Using an LLM to choose which workflows to run on schedule. While this enables dynamic behavior by selecting the right workflow for the job, it is still limited to a fixed set of pre-built workflows to select from.

python
def run_every_hour(...) # runs 0 * * * *
    for user in db.get_users()
        context = user.gather_context()
        workflows = decide_workflows_with_llm(context)
        for workflow in workflows:
            workflow.run()

2.4Beat-Schedule + LLM with Tools

But adding tools that let the LLM create custom workflows on the fly, the agent achieves true adaptability by combining tools in unlimited ways. However, this approach still wastes resources by running inference on every beat, even when there is no work to be done.

python
def run_agent(user):
    context = user.gather_context()
    done = False
    history = []
    while not done:
        tool_call = call_llm(context, history)
        done, resp = handle_tool_call(tool_call)
        history.extend([tool_call, resp])

def run_every_hour(...) # runs 0 * * * *
    for user in db.get_users():
        run_agent(user)

While this shows why dynamic workflows are required, the agent is still static across time.


3.Self-Scheduling and Wake Events

To eliminate the fixed, inefficient beat schedule, the agent needs to be able to schedule itself. After completing a workflow, the agent decides when it should wake up next:

python
next_wake = LLM.decide_sleep_duration(context)

With this approach, a simple cron job can wake agents whose sleep time has expired—similar to how operating systems handle timer interrupts. This allows the agent to allocate compute resources dynamically over time.

But pure self-scheduling creates a problem: handling external events (like user messages) is delayed until the agent wakes up. To solve this, we added wake events—signals that immediately wake up sleeping agents when something important happens:

python
if event in WakeEvents:
    wake(agent)

This hybrid model combines agent-scheduled sleep, dynamic workflow creation, and event-based interrupts—achieving both autonomy and reactivity. The architecture creates individualized timing patterns for each user while scaling computation sublinearly.

python
def run_agent(user):
    # ... everything from before ...

def wake_agent(user):
    run_agent(user)
    user.agent_sleep_until = llm_decide_sleep_until(context)
    user.save_to_db()

def run_every_min(...) # runs * * * * *
    for user in db.get_users()
        if time.now() > user.agent_sleep_until:
            wake_agent(user)

Asynchronous events provide preemptive activation mechanisms:

python
def message_webhook(...): # called on external messages
    user = user_from_identifier(...)
    wake_agent(user)

4.Decaying-Resolution Memory

Long-running agents require memory systems that evolve over time. Traditional agent systems use knowledge graphs, RAG, or context compression for memory. While these approaches can recall factually-related information and limited history, they fail to maintain truly temporal coherence across extended periods of time.

Instead, we present Decaying-Resolution Memory, a hierarchical system that summarizes interactions at different time scales. This approach achieves sublinear token scaling—memory grows much slower than interaction volume—while preserving temporal relationships.

4.1Memory Hierarchy

At any given time t, the agent's memory consists of nested summary layers. Each layer up the hierarchy covers longer time periods with less detail.

Summaries for a resolution R are generated using the results from resolution R-1. All summaries are normalized to the agent's set timezone.

Monthly
Weekly
Daily
Hourly
N-minute
Actual messages
-N mo
-10wks
-2wks
yesterday → now
Monthly
Weekly
Daily
Hourly
Minute
Messages

4.2Scaling Behavior

Simple context accumulation scales linearly O(N) with token count. Decaying-Resolution Memory scales logarithmically O(log N), maintaining long-term temporal awareness while constraining inference computational overhead.

Tokens in Context

Decaying-Resolution Memory scales approximately O(log N), providing significant efficiency gains over other naive O(N) methods.

4.3Semantic Fidelity

The system preserves high-level, important patterns ("struggled with algebra in July") while eliminating low-relevance details ("lesson started at 3:12 PM"). This selective compression works similarly to human autobiographical memory, prioritizing conceptual coherence over temporal precision.

An observed limitation of this approach, however, is direct factual recall. Decaying-Resolution Memory will perform worse on benchmarks that focus on recalling specific facts from history, especially if the existence of a fact is not continuously reinforced within the agent's immediate behavior.

4.4Ledger-Based Memory Architecture

While decaying-resolution memory is powerful, it generally must be treated like a ledger: every event that the agent perceives should be stored in memory, with very limited exceptions. When given the option, agents tend to be bad at deciding what to remember. Treating memory like a ledger shifts responsibility of memory quality from the agent to the memory system, which ends up being easier to evaluate and iteratively improve.

However, ledger-based implementations impose strict linearity constraints—agents cannot run concurrently without creating temporal inconsistencies.


5.Stateful Tools as Memory

When using decaying-resolution memory, information such as contacts, events, or long-term records should not be prioritized. Instead, these structures should live in stateful tools, mirroring the way humans offload knowledge to calendars, notebooks, or contact lists. By leveraging stateful tools as externalized memory, the agent preserves both temporal consistency and accumulated knowledge.

For example, an agent could run with a sandbox of persistent, stateful tools:

  • Dedicated messaging inbox
  • Calendar subsystem for scheduling and history
  • Contact registry with rich metadata

Offloading memory in this fashion reduces the cognitive burden on the model itself and promotes robust, long-lived state. The main engineering challenge lies in synchronizing, isolating, and scaling these stateful components alongside agent runtimes.

5.1Naming Tools

How a tool is framed—that is, its name, description, and examples—directly impacts performance. While engineers tend to think of tools as abstract functions changing the state of some system, language models reason about them semantically, drawing from patterns encountered in their training data.

Consider these functionally equivalent schemas:

json
{
  "name": "email_list_operation",
  "schema": {
    "type": "object",
    "properties": {
      "limit": {
        "type": "number",
        "description": "Limits emails returned."
      }
    }
  }
}

versus:

json
{
  "name": "check_email_inbox", 
  "schema": {
    "type": "object",
    "properties": {
      "limit": {
        "type": "number",
        "description": "Limits emails checked."
      }
    }
  }
}

The second schema uses language patterns closer to everyday phrasing— making it more likely the model "knows how" to use the tool out of the box. The first is specific to a particular system and adds extra interpretation work for the model.

Our implementation mirrors this insight: we name and document tools to reflect in-sample real-world actions, using clear task language:

  • read_message_inbox, send_message
  • manage_calendar_events
  • update_contact_book

When tool interfaces reflect familiar action names, the agent spends less effort inferring intent and more time planning. This improves reliability and efficiency.


6.Evaluation and Open Challenges

Moving logic from deterministic software to learned behavior makes evaluation extremely complex. Standard LLM benchmarks like per-prompt accuracy, factuality, and latency don't capture temporal coherence, long-term decision making, or the agent's quality of initiative.

We have found that evaluations of long-horizon agents must be done through long-term simulation, not single-step evaluation. To do this, we define a set of qualitative metrics for our use case and continuously judge our agents against them.

Our experience is that exploratory reasoning-optimized models consistently outperform models that optimize for instruction following or latency.


7.Limitations

  • Concurrency: Ledger-style memory enforces single-threaded execution per agent. Parallel runs risk temporal inconsistencies.
  • Latency and cost: Self-scheduling cuts idle compute, but wake bursts still cost. Budgets and backpressure are required.
  • Event plumbing: Missed wake events degrade responsiveness; reliable queues and retries are mandatory.
  • Memory trade-offs: Layered summaries can lose precise facts; store durable facts in tools (calendar/contacts/CRMs).
  • Scope: Validated in our domain; broader generalization needs more evidence.

8.Conclusion

Building long-horizon AI agents requires rethinking how we architect autonomy. Instead of waiting for user prompts, these systems plan, remember, and act on their own timeline.

Long-horizon architectures are computationally expensive and operationally complex, but they create agents that care—systems that take responsibility for outcomes over time, not just individual interactions.

As reasoning models improve and inference costs fall, long-horizon agents will define the next generation of AI systems: continuously attentive, self-regulating, and aligned with their users' long-term interests.

We're preparing a minimal reference for the scheduler and wake queue. If you want to collaborate on long-horizon evaluations or try this in your domain, reach out.