Production hardening

The “safe for real workloads” layer: retries with backoff for transient failures, checkpointed runs that resume after a crash, and durable local memory. All local-first — no new failure modes your provider SDK doesn’t already have.

Core concepts

Retries & backoff — RetryPolicy

Pass a RetryPolicy to retry transient model-call failures (timeouts, connection errors, rate limits, 5xx) with exponential backoff. Governance decisions (BudgetExceeded, PolicyViolation) are never retried — they’re terminal by design.

from cendor.sdk import Agent, run, RetryPolicy

agent = Agent(name="assistant", model="gpt-4o", instructions="…")
result = run(agent, "…", retry=RetryPolicy(max_attempts=5, backoff_base=0.5))
import { Agent, run, RetryPolicy } from '@cendor/sdk';

const agent = new Agent({ name: 'assistant', model: 'gpt-4o', instructions: '…' });
const result = await run(agent, '…', { retry: new RetryPolicy({ maxAttempts: 5, backoffBase: 0.5 }) });

RetryPolicy fields: max_attempts, backoff_base, backoff_factor, max_backoff, should_retry (a predicate — defaults to default_is_transient), and sleep (injectable, so tests run instantly) — camelCase in TypeScript. Only the successful attempt emits an LLMCall, so usage and cost are never double-counted.

Checkpointed & resumable runs

Pass checkpoint= (a path or a Checkpointer) and the run persists its conversation after each turn. If the process crashes, calling run again with the same checkpoint resumes from the saved state — completed tools are in the saved messages and are not re-executed:

from cendor.sdk import Agent, run

agent = Agent(name="assistant", model="gpt-4o", tools=[...], instructions="…")

# First attempt crashes mid-run; the checkpoint holds the completed turns.
try:
    run(agent, "a long task", checkpoint="run.ckpt.json")
except Exception:
    ...

# Later — same checkpoint — resumes where it left off (no re-running earlier tools):
result = run(agent, "a long task", checkpoint="run.ckpt.json")
import { Agent, run } from '@cendor/sdk';

const agent = new Agent({ name: 'assistant', model: 'gpt-4o', tools: [/* ... */], instructions: '…' });

// First attempt crashes mid-run; the checkpoint holds the completed turns.
try {
  await run(agent, 'a long task', { checkpoint: 'run.ckpt.json' });
} catch {
  // …
}

// Later — same checkpoint — resumes where it left off (no re-running earlier tools):
const result = await run(agent, 'a long task', { checkpoint: 'run.ckpt.json' });

The checkpoint is a local JSON file written atomically (temp + replace). A finished run marks it done, so a subsequent call starts fresh. Multi-agent teams checkpoint the same way — run([entry, peer, ...], input, checkpoint="team.ckpt.json") persists per turn/segment — and a run that ended without a final answer reports it via Result.incomplete.

Durable memory

Session gives in-memory conversation state with local JSON save/load; for durable, multi-conversation persistence use SQLiteSessionStore — one local file, no server. Both are covered in depth in Memory & sessions; the short version:

from cendor.sdk import Agent, run, SQLiteSessionStore

store = SQLiteSessionStore("sessions.db")
session = store.load("user-42")          # empty Session if unknown
run(agent, "hi, I'm Alice", session=session)
store.save("user-42", session)           # durable across restarts
import { Agent, run, SqliteSessionStore } from '@cendor/sdk';

const store = new SqliteSessionStore('sessions.db');
const session = store.load('user-42');   // empty Session if unknown
await run(agent, "hi, I'm Alice", { session });
store.save('user-42', session);          // durable across restarts

Plugs into the stack

Retries, checkpoints, and stores compose with everything else: a resumed run keeps its trace_id lineage, retried calls never double-count in report(), and the audit chain shows what actually executed — including the crash-and-resume seam.

Honest limits

  • No hosted runtime, server, or distributed scheduler — deliberately. The SDK is a library, like the OpenAI Agents SDK. Cross-process or distributed execution stays your job; point checkpoints and session stores at shared storage if you need handoff between machines.
  • Retries cover transport, not semantics. A model that answers badly isn’t a retryable failure — that’s what eval & regression testing is for.
  • A checkpoint saves the conversation, not your process state. Side effects your tools performed outside the run (writes, emails) are not rolled back or replayed.