Recently, I decided to build a classic AI agent for ordering pizza. The goal was simple: ask for the pizza type, ask for toppings, confirm the order, and save it. But I realized the architecture was broken. I needed a middle layer. A "Draft" area where the agent can mold the data like clay, make mistakes, fix them, and only commit when everything is perfect.Recently, I decided to build a classic AI agent for ordering pizza. The goal was simple: ask for the pizza type, ask for toppings, confirm the order, and save it. But I realized the architecture was broken. I needed a middle layer. A "Draft" area where the agent can mold the data like clay, make mistakes, fix them, and only commit when everything is perfect.

Why I Stopped Letting aI Agents Write Directly to my Database (and Built MemState)

2025/12/05 14:25

Recently, I decided to build a classic AI agent for ordering pizza. The goal was simple: ask for the pizza type, ask for toppings, confirm the order, and save it.

I  used the standard stack: LangChain, LangGraph, and SQLite. \n Here is what my first version looked like:

import sqlite3 from langchain_core.tools import tool from langchain.agents import create_agent from langchain.chat_models import init_chat_model from langgraph.checkpoint.sqlite import SqliteSaver @tool def create_order(pizza_type: str, size: str): """Create a new pizza order.""" # Simulation: Just printing, no real state management here! print(f"Creating order: {size} {pizza_type}") return "Order created." @tool def update_order(new_details: str): """Update existing order.""" return "Order updated." @tool def confirm_order(): """Call this to finalize the order.""" return f"Order sent to kitchen!" llm = init_chat_model(model="gpt-4o", model_provider="openai") agent = create_agent( llm, tools=[create_order, update_order, confirm_order], checkpointer=SqliteSaver(sqlite3.connect("agent.db", check_same_thread=False)), ) config = {"configurable": {"thread_id": "session_1"}} agent.invoke( {"messages": [("user", "I want a large Pepperoni.")]}, config=config )

\ The logic seems fine, right?

  1. User says "I want Pepperoni" → Agent calls create_order.
  2. Database executes INSERT INTO orders ....
  3. User says "No onions please" → Agent calls update_order.
  4. Database executes UPDATE orders ....

Then I realized the architecture was broken.

Imagine if the user says on step 3: "Actually, I changed my mind. I don't want pizza, I want sushi."

Now, my production database has a "dirty" record of a Pepperoni order that was never finished. I have to write logic to delete it, handle cancellations, and clean up the garbage.

I was letting the Agent's "thought process", which is chaotic and prone to mistakes, write directly to my production database. This creates Dirty Writes.

Attempt #1: Vector Memory?

Many developers suggest using tools like Mem0 or Zep. But those are for semantic memory. They help the agent remember that "Alice likes spicy food."

They do not solve the transactional state problem. Vectors cannot guarantee that my order ID is unique or that the price is a valid number.

The Solution: MemState (A "Buffer" for Agents)

I needed a middle layer. A "Draft" area where the agent can mold the data like clay, make mistakes, fix them, and only commit when everything is perfect.

I couldn't find a simple tool for this, so I built MemState.

Think of it as Git, but for Agent data:

  1. Strict Types (Pydantic): The agent cannot save garbage data.
  2. Transactions: Every change is logged. I can rollback if the agent hallucinates.
  3. Constraints: I can prevent duplicates automatically.

Here is the new Agent code:

from langchain_core.tools import tool from langchain.agents import create_agent from langchain.chat_models import init_chat_model from pydantic import BaseModel from memstate import MemoryStore, Fact, Constraint, SQLiteStorage from memstate.integrations.langgraph import MemStateCheckpointer class PizzaOrder(BaseModel): status: str = "new" pizza_type: str size: str toppings: list[str] = [] storage = SQLiteStorage("pizza_shop.db") memory = MemoryStore(storage) # 🔥 KILLER FEATURE: Singleton Constraint # A single user can have ONLY ONE active order in a single session. # If the agent attempts to create a second one, MemState will automatically update the first. memory.register_schema("order", PizzaOrder, Constraint(singleton_key="session_id")) checkpointer = MemStateCheckpointer(memory=memory) @tool def update_order(pizza_type: str, size: str, toppings: list[str]): """Call this tool to create or update the pizza order.""" # We use thread_id as a unique key (singleton_key) # In a real application, thread_id is passed through the context (config) session_id = "session_1" # The agent simply "throws" the fact. It doesn't need to check whether the order exists. # MemState will decide for itself: INSERT or UPDATE. fid = memory.commit( Fact( type="order", payload={ "session_id": session_id, "pizza_type": pizza_type, "size": size, "toppings": toppings } ) ) return f"Order state saved. Fact ID: {fid}" @tool def confirm_order(): """Call this to finalize the order.""" orders = memory.query(typename="order", json_filters={"session_id": "session_1"}) return f"Order {orders[0]['payload']} sent to kitchen!" llm = init_chat_model(model="gpt-4o", model_provider="openai") agent = create_agent( llm, tools=[update_order, confirm_order], checkpointer=checkpointer, ) config = {"configurable": {"thread_id": "session_1"}} agent.invoke( {"messages": [("user", "I want a large Pepperoni.")]}, config=config )

Why is this better?

  1. The "Draft" Concept: While the user is changing their mind ("add mushrooms", "remove cheese"), we are only updating the local MemState. My main production database stays clean.
  2. Validation: If the Agent hallucinates and tries to set the pizza price to "one million", the Pydantic schema in MemState will reject it before it corrupts the state.
  3. One Clean Write: When the user finally says "Confirm", I can simply query the final, validated JSON from MemState and do one clean INSERT into my main database.

Summary

MemState turns the chaos of a conversation into a structured transaction. It supports rollback() (Time Travel), LangGraph checkpoints, and runs on SQLite or Redis.

It’s Open Source. I would love your feedback:

https://github.com/scream4ik/MemState

Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact service@support.mexc.com for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.

You May Also Like

Metaplanet 50M Bitcoin Loan and BTC Relief Rally

Metaplanet 50M Bitcoin Loan and BTC Relief Rally

The post Metaplanet 50M Bitcoin Loan and BTC Relief Rally appeared on BitcoinEthereumNews.com. Metaplanet has secured a 50 million dollar loan using its Bitcoin holdings as collateral to fund new BTC purchases and income products. At the same time, chartist Titan of Crypto says Bitcoin’s price action continues to track a earlier relief rally fractal on the two day chart. Metaplanet secured a 50 million dollar loan backed by its existing Bitcoin holdings, according to a new disclosure shared today. The company said the funds will support additional Bitcoin purchases and expand its Bitcoin-based income operations as part of its ongoing treasury strategy. The filing shows that Metaplanet pledged part of its current holdings to obtain the loan instead of issuing new equity or bonds. This structure allows the firm to raise capital while keeping its Bitcoin position intact. It also signals that the company continues to lean heavily on Bitcoin as both a reserve asset and a financing tool. The move follows a series of Bitcoin-focused initiatives from Metaplanet, including earlier bond issuances and ongoing accumulation programs. Today’s loan marks the latest step in that strategy as the company increases leverage to expand its holdings. Analyst Sees Bitcoin Still Following Earlier Cycle Fractal Meanwhile, Crypto chartist Titan of Crypto says Bitcoin’s latest pullback still fits the “relief rally” fractal he has been tracking on the two-day chart. In a new update, he compares the current structure to the 2021–2022 cycle, highlighting a similar sequence of a local peak, a sharp drop into a demand zone, and then a rebound. Bitcoin Relief Rally Fractal Roadmap. Source: Titan of Crypto and TradingView In the chart, Bitcoin’s price action forms a pattern that mirrors the earlier cycle, with a shaded support area marking the zone where the last major relief rally started. An accompanying momentum oscillator also shows a repeat of lower highs on price…
Share
BitcoinEthereumNews2025/12/06 01:14
XRP Price Target Of $19.20 Within Six Months Still In Play, Says Analyst

XRP Price Target Of $19.20 Within Six Months Still In Play, Says Analyst

The post XRP Price Target Of $19.20 Within Six Months Still In Play, Says Analyst appeared on BitcoinEthereumNews.com. Technical analyst ALLINCRYPTO has reiterated a high-beta roadmap for XRP, arguing that chart structure and pattern symmetry could propel the token to roughly $19.20 within the next six months—while specifying a precise model target of $19.27. XRP Explosion Ahead? In a September 21 video address, he framed the move as a classic continuation sequence following a run at all-time highs and a corrective “falling wedge” that has now been retraced. “I think something like this is what you’re going to see once again… this actually could take you to that $19.27 mark,” he said, adding that his “price prediction remains the same.” The crux of the thesis is historical rhyme and pattern logic. “Just like 2017, we ran into an all-time high… and essentially, we are pulling back in and around it,” the analyst said, describing the pullback as a falling wedge—a structure he classifies as continuation when it appears in an uptrend. “The falling wedge has been completed. You have run or retraced the entire wedge… Since we engulfed that and made a target, we have now been pulling back once more, again, in the form of a falling wedge.” In his view, this sets up an “engulfment of the entire pullback… and then leads to continuation.” He also points to a potential cup-and-handle spanning the current cycle, cautioning that its measured-move objective would sit “significantly higher than $19.27,” but that his public focus is the nearer six-month path. “It’s a reliable pattern. It’s really a story of trend continuation,” he said, emphasizing that when assets “break into new all-time highs, typically they continue and will actually reach that target.” The timeline he outlines runs roughly through late March 2026. The $19.27 waypoint is not new for ALLINCRYPTO. He has repeatedly telegraphed that objective across social channels in recent…
Share
BitcoinEthereumNews2025/09/22 16:19