How to Implement Agent State Compaction and Resume in AI Suite

AI Suite provides built-in state compaction via PostgresStateStore.compact_state() to summarize historic messages into compacted records, and session resumption via Engine.resume() to restore agent conversations from persistent PostgreSQL storage with full context recovery.

The andrewyng/aisuite framework stores every agent turn in a persistent PostgreSQL state store, allowing long-running sessions to accumulate thousands of messages. To prevent performance degradation from loading massive conversation histories, AI Suite implements agent state compaction and resume capabilities that summarize old messages while maintaining seamless conversation continuity.

How State Compaction Works in AI Suite

State compaction reduces memory and I/O overhead by replacing contiguous blocks of historic messages with a single summary record.

The Compaction Process

According to the source code in aisuite/mcp/state_store.py, the compact_state() method executes a four-step transactional workflow:

  1. Collect the target slice – Fetch the specific message_id values that need compaction, typically the oldest messages already included in the model context.

  2. Generate a summary – Invoke the configured LLM provider with a summarize prompt to create summary_text.

  3. Create a CompactionRecord – Store the compaction metadata including a unique compaction_id (formatted as cmp_<uuid>), source message IDs, summary text, and a new revision number.

  4. Replace original messages – Remove the original message slice from the thread and insert a virtual placeholder message flagged as compacted.

If any step fails, the transaction rolls back leaving the thread unchanged. The method returns the new revision number for optimistic locking.

CompactionRecord Structure

The CompactionRecord captures:

  • compaction_id: Unique identifier (cmp_<uuid>)
  • source_message_ids: Original message identifiers
  • summary_text: LLM-generated summary content
  • revision: Thread revision number after compaction

Key Implementation

The core logic resides in aisuite/mcp/state_store.py:

from aisuite.mcp.state_store import PostgresStateStore
from uuid import uuid4

def compact_state(self, thread_id: str, source_message_ids: List[str], reason: str) -> CompactionRecord:
    # Gather messages

    messages = self._fetch_messages(thread_id, source_message_ids)
    
    # Summarise via LLM provider

    summary = self.provider.summarise(messages)
    
    # Build record

    record = CompactionRecord(
        compaction_id=f"cmp_{uuid4().hex}",
        source_message_ids=source_message_ids,
        summary_text=summary,
        reason=reason,
        revision=self._next_revision(thread_id),
    )
    
    # Store & replace

    self._save_compaction(record)
    self._replace_with_placeholder(thread_id, record)
    return record

How Session Resumption Works

The Engine.resume() method in aisuite/framework/engine.py restores agent state from persistent storage, handling both regular messages and compacted placeholders.

Loading Thread State

When resuming, the engine calls store.get_thread_head(thread_id) to retrieve the latest revision, model context message IDs, and compaction metadata. It then loads the actual message content via load_messages().

Expanding Compacted Messages

Compacted messages remain collapsed until the LLM requests the full context. The engine lazily invokes self._expand_compacted(messages) to retrieve summaries from CompactionRecord entries on-demand, rather than expanding all historic compactions at once.

Durable Resume for Pending Tools

If the previous session ended while waiting for user approval or tool execution, the durable resume mechanism automatically replays pending ToolResult objects. This allows the conversation to continue without requiring the user to re-approve already authorized actions.

Resume Implementation

The resumption logic in aisuite/framework/engine.py follows this pattern:

async def resume(self, thread_id: str) -> None:
    head = await self.state_store.get_thread_head(thread_id)
    messages = await self.state_store.load_messages(head.model_context_message_ids)
    
    # Expand compacted placeholders if the LLM requests them

    self._expand_compacted(messages)
    
    # Replay any pending tool results (durable resume)

    await self._replay_pending_tool_results(thread_id)
    
    self.current_thread = Thread(messages=messages, revision=head.revision)

Complete Implementation Workflow

Combine compaction and resume to manage long-running agent sessions efficiently.

1. Compact State

Manually trigger compaction when sessions exceed configurable thresholds (e.g., >200 messages):

from aisuite.mcp.state_store import PostgresStateStore

store = PostgresStateStore(dsn="postgresql://user:pass@localhost/aisuite")
thread_id = "t_12345"

# Compact the first 50 messages

message_ids = store.head(thread_id).model_context_message_ids[:50]
compacted = store.compact_state(
    thread_id=thread_id,
    source_message_ids=message_ids,
    reason="Session optimization - reduce memory footprint"
)

print(f"Created compaction {compacted.compaction_id}, revision {compacted.revision}")

2. Resume Session

Restore the conversation and continue processing:

from aisuite.framework import Engine

engine = Engine(state_store=store, provider=your_llm_provider)

# Re-hydrate engine, expand compacted placeholders as needed,

# and re-execute any pending tool calls

await engine.resume(thread_id)

# Continue conversation seamlessly

await engine.send_user_message("Summarize our previous discussion")

Key Implementation Files

Summary

  • State compaction in andrewyng/aisuite uses PostgresStateStore.compact_state() to summarize message blocks into CompactionRecord entries, replacing original messages with virtual placeholders.
  • Session resumption relies on Engine.resume() in aisuite/framework/engine.py to restore thread state, lazily expand compacted messages, and replay pending tool results.
  • Compaction triggers automatically based on message count thresholds or manual invocation, with full transactional safety ensuring data integrity.
  • The durable resume feature automatically handles interrupted tool executions, eliminating the need for users to re-approve actions after reconnection.

Frequently Asked Questions

What triggers state compaction in AI Suite?

Compaction triggers either manually through direct compact_state() invocation or automatically when session message counts exceed configurable limits (typically 200 messages). The system targets the oldest messages already incorporated into the model context to minimize impact on recent conversation history.

How does AI Suite handle compacted messages during resume?

During Engine.resume(), compacted messages remain as virtual placeholders in the initial message list. The engine expands them on-demand via _expand_compacted(messages) only when the LLM requires access to the summarized historical context, optimizing memory usage during session restoration.

What is durable resume and when does it occur?

Durable resume automatically replays pending ToolResult objects when restoring sessions that were interrupted during tool execution or user approval workflows. This occurs in Engine.resume() through _replay_pending_tool_results(), allowing conversations to continue without requiring users to re-approve actions after application restarts or network reconnections.

Where is agent state stored in AI Suite?

Agent state persists in PostgreSQL by default through the PostgresStateStore class in aisuite/mcp/state_store.py. This includes raw messages, CompactionRecord entries, thread revision numbers, and pending tool results, enabling durable resumption across application restarts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →