This article was originally published on[BuildZn].
Building persistent AI agents that don't hemorrhage cash or forget everything? Spent too much time wrestling with serverless functions and container restarts. Here's how a durable cloud cell AI agent architecture changed the game for me. Everyone talks about the dream of truly intelligent assistants, but nobody gets real about the infrastructure nightmare behind keeping them online, stateful, and affordable. I figured it out the hard way, building stuff like FarahGPT which needs to remember complex trading strategies across long sessions.
Look, we've all been there. You build this awesome AI agent, maybe a custom Claude assistant, that needs to remember user preferences, maintain long conversation history, or track complex state for a multi-step process. Then you try to deploy it.
Here's the usual suspects and why they fail for truly stateful, persistent AI agents:
persistent claude assistant
across container restarts is a chore.The core issue with these traditional setups for AI agents is their fundamental mismatch with statefulness. AI agents, especially those meant for complex tasks or long-term interaction, thrive on maintaining an evolving internal state. Losing that state on every interaction or paying constantly for it to exist is just broken.
Here's what a durable cloud cell architecture brings to the table:
Think of a durable cloud cell not as a server or a function, but as a tiny, dedicated, intelligent brain in stasis. It's a serverless compute environment that uniquely preserves its entire memory, including variables, objects, and open connections, when it goes idle. When an event (like an API call from your frontend) wakes it up, it resumes execution exactly where it left off, with all its in-memory state intact. It's like pausing a program and then unpausing it days later, without losing any data. This is what makes a nanoclaw architecture
or similar platforms like OnCell so powerful for stateful agents.
Unlike a serverless function that initializes from scratch and loads state from a DB, a durable cell is the state. It's the execution environment and its full memory image, saved and restored on demand. This drastically simplifies how you build serverless ai agents
that need to remember things. You don't need to manually save and load agent memory to a database on every request. The platform handles it.
When your agent isn't active, the cell "sleeps," consuming virtually no resources, hence the zero idle cost AI. When a request comes in, it "wakes up," and your agent instantly has access to its full memory, including its entire conversational history, learned preferences, or complex internal models.
Let's get practical. I'll show you how to set up a basic durable cloud cell AI agent
using Node.js, focusing on the agent logic and how you'd interact with a durable cell platform like OnCell (conceptually, as the specific SDK might vary).
First, your agent's core logic lives inside the durable cell. This is where your AI orchestration, LLM calls, and state management happen.
// agent_logic_in_cell.js (This code runs inside your durable cloud cell)
const { Anthropic } = require('@anthropic-ai/sdk'); // Or OpenAI, etc.
const anthropic = new Anthropic({ apiKey: process.env.CLAUDE_API_KEY });
// This `state` object persists automatically across cell invocations.
// It's part of the cell's preserved memory.
let agentState = {
conversationHistory: [],
userPreferences: {},
taskContext: null, // e.g., current trading goal for FarahGPT
initialized: false
};
// This function is the entry point for your cell when it's invoked.
// It receives input from your external orchestrator.
async function processAgentRequest(input) {
if (!agentState.initialized) {
console.log("Agent initializing for the first time or after a deep sleep.");
// Perform one-time setup here if needed, e.g., initial configs
agentState.initialized = true;
}
const { userId, message, action, params } = input;
// Load user preferences if not already in memory (or periodically update)
if (!agentState.userPreferences[userId]) {
// In a real app, you might fetch this from a lightweight DB for global preferences
// or let the agent learn them over time within its cell state.
agentState.userPreferences[userId] = { favoriteColor: 'blue' };
}
agentState.conversationHistory.push({ role: 'user', content: message });
let agentResponse = { text: "Sorry, I couldn't process that.", data: null };
try {
if (action === 'trade_query') {
// Example: FarahGPT style logic
agentResponse = await handleTradeQuery(userId, params);
} else {
// General conversation with Claude
const messages = agentState.conversationHistory.map(entry => ({
role: entry.role === 'user' ? 'user' : 'assistant',
content: entry.content
}));
const claudeResponse = await anthropic.messages.create({
model: "claude-3-opus-20240229", // Or your preferred Claude model
max_tokens: 1024,
messages: messages
});
agentResponse.text = claudeResponse.content[0].text;
agentState.conversationHistory.push({ role: 'assistant', content: agentResponse.text });
}
} catch (error) {
console.error("Agent processing error:", error);
agentResponse.text = "An internal error occurred. Please try again.";
}
// Agent's internal state (agentState) is automatically saved by the durable cell platform.
return {
response: agentResponse.text,
agentData: agentResponse.data,
updatedHistoryLength: agentState.conversationHistory.length
};
}
async function handleTradeQuery(userId, params) {
// This is where FarahGPT's multi-agent architecture or core logic would live.
// It could interact with external APIs, perform calculations, etc.
// Example:
console.log(`User ${userId} requested trade query with params:`, params);
// Simulate complex AI decision making
const decision = {
action: 'HOLD',
asset: params.asset || 'GOLD',
reason: 'Market looks volatile, awaiting confirmation signals.',
confidence: 0.75
};
agentState.taskContext = { lastDecision: decision }; // Persist this context
return {
text: `Based on current analysis, I recommend to ${decision.action} on ${decision.asset}. Reason: ${decision.reason}.`,
data: decision
};
}
// Export the main function for the cell to call
module.exports = processAgentRequest;
Now, from your external Node.js backend (e.g., a Next.js API route, a Flutter backend), you'll interact with this durable cell. You don't directly run the agent_logic_in_cell.js
file. Instead, you send inputs to the cell via its API.
// external_orchestrator.js (Your Node.js backend)
const axios = require('axios'); // For making HTTP requests to your cell platform API
// Assume these are configured in your environment variables
const ONCELL_API_ENDPOINT = process.env.ONCELL_API_ENDPOINT || 'https://api.oncell.dev/v1/cells';
const ONCELL_API_KEY = process.env.ONCELL_API_KEY;
const AGENT_CELL_ID = process.env.AGENT_CELL_ID; // The ID of your deployed durable cell
async function invokeDurableCellAgent(userId, message, action = 'chat', params = {}) {
if (!ONCELL_API_KEY || !AGENT_CELL_ID) {
throw new Error("OnCell API key or Cell ID not configured.");
}
try {
console.log(`Invoking agent cell ${AGENT_CELL_ID} for user ${userId}...`);
const response = await axios.post(
`${ONCELL_API_ENDPOINT}/${AGENT_CELL_ID}/invoke`,
{
// This 'input' object is passed directly to the `processAgentRequest` function in your cell.
userId: userId,
message: message,
action: action,
params: params
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${ONCELL_API_KEY}`
}
}
);
const { response: agentResponseText, agentData, updatedHistoryLength } = response.data;
console.log("Agent cell invocation successful.");
console.log("Agent Response:", agentResponseText);
console.log("Updated History Length:", updatedHistoryLength);
return {
responseText: agentResponseText,
agentSpecificData: agentData,
historyLength: updatedHistoryLength
};
} catch (error) {
console.error("Error invoking durable cell agent:", error.response ? error.response.data : error.message);
throw new Error(`Failed to invoke agent: ${error.response ? error.response.statusText : error.message}`);
}
}
// Example usage from your application
async function main() {
const USER_ID = 'user_123';
// First interaction: Agent wakes up, processes, state is saved.
console.log("\n--- First Interaction ---");
try {
const result1 = await invokeDurableCellAgent(USER_ID, "What's your current recommendation for gold?");
console.log("Result 1:", result1.responseText);
} catch (e) {
console.error(e.message);
}
// Simulate some idle time, cell goes to sleep, then wakes up with state intact.
console.log("\n--- After some idle time (cell sleeps and wakes up) ---");
// This second call will find the agent's state (including conversationHistory and taskContext) intact.
try {
const result2 = await invokeDurableCellAgent(USER_ID, "What was that reasoning again?", 'chat');
console.log("Result 2:", result2.responseText);
} catch (e) {
console.error(e.message);
}
// Another interaction with a specific action
console.log("\n--- Specific Action Interaction ---");
try {
const result3 = await invokeDurableCellAgent(USER_ID, "Check the market for Ethereum.", 'trade_query', { asset: 'ETH' });
console.log("Result 3:", result3.responseText);
} catch (e) {
console.error(e.message);
}
}
main();
This setup means your durable cloud cell AI agent
handles all its internal state without you needing to worry about explicit database writes for conversation history or temporary context. The external orchestrator simply sends messages and receives responses. The magic of persistence happens under the hood.
When I first started playing with durable cells, I made a classic mistake: I treated them like glorified serverless functions with a database bolted on. I was trying to manually save agentState
to a separate MongoDB instance on every invocation, thinking the cell just provided a runtime. This is fundamentally wrong. The whole point of a durable cell is that it preserves its entire runtime memory – all the variables, objects, and their values – automatically. My external MongoDB was redundant for internal agent state and just added complexity.
Another pitfall, specific to platform configuration, hit me hard. I once spent hours debugging why an agent wasn't retaining complex in-memory graph structures across invocations, thinking it was a cell issue or some weird Node.js garbage collection. Turns out, the default maxIdleTime
on our OnCell setup was set to 300s
(5 minutes), and I was hitting this soft timeout. For long-running, conversational agents that might have users for a coffee break or switch apps, 5 minutes is nothing. I had to manually set agent.config.maxIdleTime = 1800
(30 minutes) on specific agent instances to ensure complex state graphs persisted through user s. This isn't always highlighted in basic setup guides, but it's critical for true conversational continuity and avoiding unnecessary re-initialization of complex internal structures. Without adjusting this, your persistent claude assistant
won't actually be all that persistent if your users aren't constantly interacting with it.
While durable cells offer zero idle cost AI
, you still pay for active compute time and persistent storage. Here's how to keep things lean:
maxIdleTime
:maxIdleTime
too low can cause your agent to reset its in-memory state more often than desired for long user sessions. Setting it too high means your cell stays "warm" (and thus billable) for longer periods of true inactivity. Find the sweet spot based on your user interaction patterns.Q: How does a durable cloud cell compare to a serverless function with a database?
A: A serverless function combined with a database requires you to explicitly manage what data is saved and loaded. A durable cloud cell, however, preserves the entire runtime memory of your agent. This means all your in-memory variables and objects are automatically retained, simplifying state management significantly for persistent claude assistant
scenarios.
Q: Can I use any LLM with a durable cloud cell AI agent?
A: Yes, absolutely. A durable cloud cell provides a Node.js (or other runtime) environment. You can integrate any LLM by making API calls to services like OpenAI, Anthropic (Claude), or even local Ollama instances from within your agent's code running inside the cell. The cell just provides the execution and persistence layer.
Q: What are the main cost benefits of zero idle cost AI?
A: The primary cost benefit is that you only pay when your AI agent is actively processing requests. When the agent is waiting for user input or other events, the durable cell automatically "sleeps" and incurs no compute costs. This dramatically reduces the operational expenses compared to traditional always-on servers or container instances, especially for agents with intermittent usage patterns.
This durable cloud cell AI agent
architecture isn't just a fancy buzzword; it's a fundamental shift in how we build and deploy stateful AI agents. It fixes the core problems of persistence and cost that have plagued traditional setups. If you're building an AI agent that needs to remember who it is and what it's doing without costing a fortune, this is the way forward. Anything less is just building more tech debt.
Interested in seeing how this could work for your specific AI product or need a custom agent built? Let's chat. Book a call with me at buildzn.com/contact.