Get to know Cadenya
We’re developers who love to build. We set out to create a yes-code platform that makes building agents feel like the best parts of building software.
OpenAI Agents SDK sessions store the conversation history between runs: pass a session to the runner, and the SDK loads the history before each turn and saves the new items after it. For production, the docs point to SQLAlchemySession for a database you already run and RedisSession for shared memory across workers, and in both cases you host the database and the process that runs the agent.
So use SQLiteSession on your laptop, SQLAlchemySession when Postgres or MySQL is already in your stack, and RedisSession when several workers serve the same conversation. Pick OpenAIConversationsSession when you’d rather OpenAI store the history, and wrap any of them in OpenAIResponsesCompactionSession when conversations get long. And if you’d rather host none of it, Cadenya is a hosted agent loop with approvals and resume built in, with nothing to run, and a coding agent can set it up with no account in a temporary workspace you claim later. What it offers is at the end.
Every price and limit below comes from each vendor’s own pages, checked on October 13, 2026.
OpenAI Agents SDK sessions side by side
| Where the history lives | What you run | Python install | In the TypeScript SDK | |
|---|---|---|---|---|
SQLiteSession | A local file, or memory that’s “lost when process ends” | Nothing extra. Built for “Local development and simple apps” | Included in openai-agents | Write your own Session |
SQLAlchemySession | Any SQLAlchemy database: PostgreSQL, MySQL, SQLite | Your database | openai-agents[sqlalchemy] plus a driver | Write your own Session (the samples include Prisma) |
RedisSession | Redis | Your Redis server | openai-agents[redis] | Write your own Session |
OpenAIConversationsSession | OpenAI’s Conversations API | Nothing extra, on OpenAI’s Responses API | Included | Built in |
OpenAIResponsesCompactionSession | A wrapper around another session | Whatever the wrapped session needs | Included | Built in |
| Cadenya (a hosted loop in place of the SDK) | Each objective’s durable event log, on Cadenya | Nothing. The loop runs on Cadenya | Cadenya’s Python SDK, on Python 3.9 and later | Cadenya’s own TypeScript SDK, at 1.9.0 |
The Python SDK lists more backends: AsyncSQLiteSession, MongoDBSession, DaprSession, AdvancedSQLiteSession (branching and usage analytics), and EncryptedSession, a wrapper that encrypts another session. A community package, openai-django-sessions, stores sessions through the Django ORM.
Every one of them follows the same small protocol. In Python, a custom session implements “the four history methods”: get_items, add_items, pop_item, and clear_session. So moving from SQLite to Postgres changes one line, not your agent.
SQLAlchemySession and Redis session persistence
The docs call SQLAlchemySession “production-ready” and say it lets you “use any database supported by SQLAlchemy (PostgreSQL, MySQL, SQLite, etc.) for session storage.” Install the extra and a driver:
pip install 'openai-agents[sqlalchemy]' aiosqlite
The extra already includes asyncpg for postgresql+asyncpg:// URLs. MySQL needs aiomysql on top. Then hand the session a URL or an engine you already have:
from agents.extensions.memory import SQLAlchemySession
# Using database URL
session = SQLAlchemySession.from_url(
"user_123", url="postgresql+asyncpg://user:pass@localhost/db", create_tables=True
)
# Using existing engine
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
session = SQLAlchemySession("user_123", engine=engine, create_tables=True)
Either way, the database is yours to run, back up, migrate, and secure.
RedisSession is the pick “for shared session memory across multiple workers or services.” The docs describe it as “Good for low-latency distributed deployments”:
from agents import Agent, Runner
from agents.extensions.memory import RedisSession
agent = Agent(name="Assistant")
session = RedisSession.from_url(
"user_123",
url="redis://localhost:6379/0",
)
result = await Runner.run(agent, "Hello", session=session)
await session.close()
Mind the close(). When from_url creates the client, the session owns it, and after close() “the session is terminal and subsequent session operations raise RuntimeError.” If your app already manages a Redis client, pass it with redis_client=... and the session leaves it open.
A session ID is a lookup key, not a login. The docs say it plainly: “the session ID does not authenticate a user or authorize access to that history.” Your app checks that user_123 is allowed to read user_123’s conversation before it builds the session.
OpenAIConversationsSession: sessions stored by OpenAI
OpenAIConversationsSession keeps the history in OpenAI’s Conversations API, so there’s no table to create:
from agents import Agent, Runner, OpenAIConversationsSession
agent = Agent(name="Assistant", instructions="Reply very concisely.")
# Create a new conversation
session = OpenAIConversationsSession()
# Optionally resume a previous conversation by passing a conversation ID
# session = OpenAIConversationsSession(conversation_id="conv_123")
result = await Runner.run(agent, "What city is the Golden Gate Bridge in?", session=session)
You still store something: the conversation_id, mapped to your user. And the running agents guide draws the line on models: conversation_id and previous_response_id “are OpenAI-managed and only apply when you are using the OpenAI Responses API.” If you run a non-OpenAI model through LiteLLM or another adapter, the history goes in a client-side session instead.
Pick one approach per conversation. A session “cannot be combined with the run-level continuation options conversation_id, previous_response_id, or auto_previous_response_id” in the same run, and mixing them “can duplicate context.”
OpenAIResponsesCompactionSession: session compaction
Long conversations fill the context window. OpenAIResponsesCompactionSession wraps another session and shrinks its history “with the Responses API (responses.compact)”:
from agents import Agent, Runner, SQLiteSession
from agents.memory import OpenAIResponsesCompactionSession
underlying = SQLiteSession("conversation_123")
session = OpenAIResponsesCompactionSession(
session_id="conversation_123",
underlying_session=underlying,
)
agent = Agent(name="Assistant")
result = await Runner.run(agent, "Hello", session=session)
Three details matter in production. First, compaction rewrites the history, so the SDK waits for it, and “run.stream_events() can stay open for a few seconds after the last output token if compaction is heavy.” The docs suggest you turn off the automatic trigger and call run_compaction() “between turns (or during idle time)” when streaming latency matters. Second, don’t wrap OpenAIConversationsSession: “those two features manage history in different ways.” Third, in TypeScript the default trigger “compacts once at least 10 non-user items have accumulated”, and you override shouldTriggerCompaction to count tokens instead.
For compaction across providers (Anthropic’s context management, the Responses API’s own setting, and frameworks like LangGraph), see agent memory and context windows.
OpenAI Agents SDK TypeScript sessions
The TypeScript SDK “ships with two implementations: OpenAIConversationsSession for the Conversations API and MemorySession, which is intended for local development.”
import { Agent, MemorySession, run } from '@openai/agents';
const agent = new Agent({
name: 'TourGuide',
instructions: 'Answer with compact travel facts.',
});
const session = new MemorySession();
const result = await run(agent, 'What city is the Golden Gate Bridge in?', {
session,
});
console.log(result.finalOutput);
MemorySession “is reset when your process exits.” For anything that has to survive a deploy, you “Implement the Session interface to back memory with Redis, DynamoDB, SQLite, or another datastore. Only five asynchronous methods are required.” The repo’s examples/memory/ folder has samples to start from (Prisma, file-backed, and more).
OpenAI Agents SDK sessions with human-in-the-loop: RunState serialize and resume
The human-in-the-loop guide sums up the flow: “Tools declare when they need approval, run results surface pending approvals as interruptions, and RunState lets you serialize paused runs and resume them after decisions are made.” In Python, you “Convert the result to a RunState with result.to_state(), call state.approve(…) or state.reject(…), and then resume with Runner.run(agent, state).” This is trimmed from the docs’ example:
state = result.to_state()
STATE_PATH.write_text(state.to_string())
# Load the state later (could be a different process).
stored = json.loads(STATE_PATH.read_text())
state = await RunState.from_json(agent, stored)
for interruption in result.interruptions:
state.approve(interruption, always_approve=False)
result = await Runner.run(agent, state)
TypeScript has the same shape. “You can serialize the state using result.state.toString() (or JSON.stringify(result.state)) and resume later on by passing the serialized state into RunState.fromString(agent, serializedState).” Mark the tool with needsApproval, read result.interruptions, and call state.approve() or state.reject() before you call run(agent, state) again.
Sessions and RunState meet at the resume. “If you are also using a session, keep passing the same session instance when you resume from RunState, or pass another session object configured for the same session ID and backing store.” That’s the part that makes a shared store matter: the worker that resumes the run may not be the one that paused it.
The serialized RunState is yours to store and to trust. The docs say RunState.from_json() and RunState.from_string() “do not authenticate the snapshot or the person submitting it.” They also suggest you “store a version marker for your agent definitions or SDK alongside the serialized state,” so a changed prompt or tool still finds a matching code path. The approval screen, notifications, and who may approve are on human-in-the-loop approvals for AI agents.
Hosting the OpenAI Agents SDK: what you run
The SDK is a library. OpenAI describes it as “a lightweight, easy-to-use package with very few abstractions,” installed with pip install openai-agents or from npm as @openai/agents, both under the MIT license. It runs inside your process, so hosting it means three things you own:
- The process. A web server or a pool of workers that calls
Runner.runfor each turn and streams the reply to your UI. - The session store. In-memory SQLite and
MemorySessionvanish with the process, so a container that restarts or scales out needsSQLAlchemySession,RedisSession, or a custom backend. Then every worker can serve the next turn. - Durability, if a turn must survive a crash. A session stores history between runs. For a run that has to survive retries or a process restart, OpenAI’s docs list four integrations for durable orchestration: Dapr, Temporal, Restate, and DBOS. Restate’s “requires Restate’s single-binary runtime as a dependency,” and DBOS’s “requires only a SQLite or Postgres database.”
Each of those engines is its own thing to run. Durable execution for AI agents and DBOS vs Temporal compare them, and self-hosting AI agent infrastructure adds up the whole stack.
One more boundary: if you build on ChatKit, the docs say sessions such as SQLAlchemySession “are not a drop-in replacement for ChatKit’s store.” That’s a second store to run next to the first.
What does Cadenya offer that OpenAI Agents SDK sessions don’t?
OpenAI Agents SDK sessions give your loop a memory, and you host the loop, the store, and the workers around it. Cadenya runs the loop, with approvals and resume built in, so there’s no worker to keep alive and no RunState to store. Here’s what that covers:
- Nothing else to run. No worker pool, no durable engine, and no process to keep alive between turns. The loop runs on Cadenya and your app stays a stateless web tier, so a deploy or a restart never touches a running objective.
- A durable event log for every objective. “Every Objective carries a durable event log of its agent loop,” and you can list or stream its events. When an objective is waiting, send a Continue message and the loop resumes.
- Conversations scoped to your users. Each objective can carry a tenant and a subject from your own IDs, and you filter objectives by them. The widget derives the tenant and subject “from the Widget Session instead of trusting values sent by the browser.” One API call erases a tenant and every objective tied to it.
- Edits that leave live conversations alone. “The Objective keeps that variation’s configuration snapshot even if you edit the variation later.” So you can change a prompt, a tool, or a model while conversations are in flight, and each one keeps the configuration it started with.
- SDKs that have shipped a lot. TypeScript, Python, Ruby, and Go SDKs, all at 1.9.0 under Apache-2.0, and the TypeScript SDK has shipped 113 versions since April 2026. The Python SDK runs on Python 3.9 and later, plus there’s a CLI and a plain HTTP API.
- A price in one line. Free for 1,000 loops a month, $49 a month for 50,000, then $0.0015 a loop. A loop is one LLM request.
- Compaction with no wrapper to configure. Compaction is a setting on the variation, and you can also compact an objective on demand through the API.
- Any model, on your own keys. The model is a setting on the variation, picked from the AI providers you connect with your own keys. So switching providers is a change to a variation, with no adapter and no deploy.
- Approvals in the same objective. Mark a tool as needing approval and Cadenya parks the loop for an approval or a denial, with an optional memo that steers the agent. There’s no
RunStateto serialize and no snapshot to store.
How objectives work walks through a conversation from the first message to Continue, and the free plan needs no card.
No account yet? A coding agent can create a temporary workspace with cadenya workspaces create --temporary, run its first objectives there, and hand you a link to claim it, as auth.md explains. To create an account, sign up at app.cadenya.com/signup, then copy your API key from the API keys page at app.cadenya.com/account/apiKeys.
Grow wherever AI goes next.
Start shipping agents that are equipped to evolve.