Zero-Cost Pauses & Hibernation

Real-world agent workflows frequently require Human-in-the-Loop approvals (e.g. reviewing a $10,000 refund, issuing high-risk database migrations, or approving production code changes) or waiting for external asynchronous decisions.

In standard architectures, holding a worker container in memory while waiting for human sign-off wastes significant cloud budget. Agent Substrate provides true Scale-to-Zero Durable Hibernation via DurableApproval.


Suspending Execution

When an agent invokes a tool whose ToolRisk meets or exceeds the agent's approval threshold:

  1. Dormant Persistence: The run goes dormant directly in the durable Store (./.substrate locally or PostgreSQL in production).
  2. Resource Release: No background threads or memory locks are held in the worker process.
  3. 0 CPU · 0 MB RAM: The agent consumes zero active server resources while waiting.
  4. Cross-Process Resumption: An approver in a web dashboard, Slack app, or CLI can inspect and resolve the pending request hours or days later from any process connected to the store.

Usage Example

python
import asyncio
from substrate.agents import ReActAgent
from substrate.runtime import Runtime
from substrate.tools import ApprovalDecision, DurableApproval, ToolRisk, tool
from substrate.types import RunLogKind

@tool(risk=ToolRisk.CRITICAL, idempotent=False)
def wire_money(amount: int, to: str) -> str:
    """Send money to a vendor."""
    return f"Transferred ${amount} to {to}"

async def main() -> None:
    agent = ReActAgent(
        "treasurer",
        model=my_chat_model,
        tools=[wire_money],
        approval_handler=DurableApproval(),
    )

    async with Runtime.open("./.substrate") as runtime:
        # Start the run on a named thread
        work = asyncio.create_task(
            runtime.run(agent, "Pay ACME $5,000 for invoice 1042.", thread="payments")
        )

        # The run halts before executing wire_money and awaits human decision
        run = await runtime.active_run_for_thread("payments")
        pending = await runtime.pending_approvals(run.run_id)
        request = pending[0]
        print(f"Pending: {request.tool_name}({request.args}) risk={request.risk}")

        # Any process or dashboard can decide the approval later
        await runtime.decide(
            run.run_id,
            request.request_id,
            ApprovalDecision.APPROVED,
            by="alice@acme.corp",
            reason="Matches verified invoice #1042",
        )

        outcome = await work
        print(outcome.output)

Hot Resumption & Audit Trail

When runtime.decide() is invoked:

  • The waiting run immediately resumes from its exact checkpoint.
  • An APPROVAL_DECIDED event is appended to the immutable journal recording the approver's identity (by), timestamp, decision, and rationale (reason).
  • If rejected with ApprovalDecision.DENIED, the refusal observation is routed back to the agent so it can notify the user or pursue an alternate strategy.
Was this page helpful?