An advanced chatbot backend by MereskaAI, built to support scalable, intelligent, and memory-aware conversational AI services.
MemoraWeave is a backend foundation for building conversational AI systems that need more than simple request-response interactions. It is designed for chatbot and agent-based applications that require persistent context, thread-based memory, tool usage, and flexible LLM orchestration.
This repository is currently in its early stage and provides the base structure for a scalable AI backend that can evolve into a production-ready system.
Modern AI assistants need to do more than generate responses. They need to:
- remember previous interactions
- manage multi-turn conversations across threads or sessions
- integrate with external tools and workflows
- support multiple model providers
- scale reliably as a backend service
MemoraWeave is intended to solve those needs through a modular and extensible architecture.
- Build a memory-aware conversational backend
- Support thread-based conversation management
- Enable LLM orchestration across different providers
- Provide a clean foundation for tool-calling and agent workflows
- Keep the system extensible, scalable, and developer-friendly
The project is intended to support capabilities such as:
- Thread-based memory management
- Persistent conversation state
- Multi-session chatbot flows
- API-first backend architecture
- LLM provider integrations
- Tool-calling workflows
- Agentic orchestration patterns
- PostgreSQL-backed data persistence
Based on the current project direction, MemoraWeave is aligned with technologies such as:
- Python
- FastAPI
- PostgreSQL
- LangChain
- LangGraph
- Gemini
- Ollama
Note: Some integrations may still be under development depending on the current implementation status.
.
├── .python-version
├── CHANGELOG.md
├── LICENSE
├── README.md
├── main.py
└── pyproject.toml
- main.py — main application entry point
- pyproject.toml — project metadata and dependency configuration
- CHANGELOG.md — project change history
- LICENSE — repository license
- .python-version — local Python version reference
Make sure you have:
- Python installed
pipavailable- PostgreSQL installed and running
- Access to any required LLM provider credentials
Clone the repository:
git clone https://github.com/<your-username>/MemoraWeave.git
cd MemoraWeaveCreate and activate a virtual environment:
python -m venv .venv
source .venv/bin/activateInstall dependencies:
pip install -e .Or, if editable install is not needed:
pip install .Before running the project, prepare your environment variables or application config for things like:
- database connection
- app environment
- model provider credentials
- memory/session configuration
- API host and port
A typical setup may include:
APP_ENV=development
DATABASE_URL=postgresql://user:password@localhost:5432/memoraweave
LLM_PROVIDER=geminiAdjust the configuration keys based on the actual implementation in your codebase.
For the current scaffold, you can start with:
python main.pyIf the app is later exposed as a FastAPI/ASGI service, you may switch to a command like:
uvicorn app.main:app --reloadUse the command that matches your actual application entrypoint.
MemoraWeave is suitable for systems such as:
- AI customer support backends
- internal knowledge assistants
- memory-aware chat applications
- multi-session AI copilots
- agent-based automation services
- LLM backends with persistent conversational context
Planned areas of development may include:
- Core API endpoints
- Persistent memory engine
- Session and thread management
- PostgreSQL integration
- LLM provider abstraction
- Tool-calling support
- Agent workflow orchestration
- Authentication and access control
- Logging and observability
- Testing and CI/CD pipeline
Contributions are welcome.
To contribute:
- Fork the repository
- Create a feature branch
- Commit your changes
- Open a pull request
Please make sure your changes are clear, tested, and aligned with the project direction.
Project changes and updates are tracked in CHANGELOG.md.
This project is licensed under the MIT License. See LICENSE for details.
Built and maintained by MereskaAI.
This repository is currently in an early development phase. The current structure serves as a foundation for future implementation and expansion.
This project uses PostgreSQL with the pgvector extension for data and vector storage. We also provide pgAdmin for easy database management.
Start the containers using docker-compose:
docker-compose up -dWe have integrated an automatic SQL migration service (memoraweave_migrate) directly into the docker-compose.yml. This service runs an idempotent bash script (app/db/run_migrations.sh) that checks the app/db/sql directory and applies any .sql files that haven't been executed yet, tracking them in the app.schema_migrations table.
- To see the migration logs:
docker compose up migrate
- To add a new schema change, simply create a new numbered
.sqlfile inapp/db/sql/(e.g.,003_add_new_table.sql) and rundocker compose up migrate. The system will automatically detect and apply the new file without needing to wipe the database.
Once the containers are running, you can access the pgAdmin interface in your browser:
- URL: http://localhost:5050
- Email:
admin@admin.com - Password:
admin
The database server (MemoraWeave DB) is fully pre-configured. It will automatically appear under the Servers group in the left sidebar, and you can connect to it directly without entering any passwords!
To start the FastAPI application for development with auto-reload enabled, run:
uvicorn app.main:app --reloador if using uv
uv run uvicorn app.main:app --reloadOnce the server is running, you can verify that the API is responding correctly by visiting the health check endpoint:
- Endpoint: http://127.0.0.1:8000/api/v1/health
Expected Response:
{
"status": "ok",
"service": "memoraweave-api"
}In this phase, we focus on setting up the database tables for the application's UI and chat history. This is separate from LangGraph's internal persistence and serves as the source of truth for the product history.
We implement three core tables:
app.chat_threads: Stores the list of conversation threads (useful for sidebars).app.chat_messages: Stores the full chat transcript.app.chat_events: Logs granular execution events (tool calls, streaming chunks, errors).
The schema is defined in app/db/sql/001_init_app_chat.sql.
- Thread-based: All messages and events are linked to a unique
thread_id. - Logical Turns: Messages are grouped by
turn_idto handle complex interactions (user input -> multiple tools -> assistant response) as a single unit. - Separation of Concerns: Events are kept in a separate table to keep the UI's message history clean and efficient.
To initialize the schema in your local PostgreSQL instance, you can use the following command:
psql "postgresql://postgres:postgres@localhost:5432/memoraweave" -f app/db/sql/001_init_app_chat.sqlNote
Ensure your PostgreSQL service is running and the database memoraweave (or your chosen name) exists before running the command.
If you are using an external PostgreSQL instance (e.g., on a VPS), the setup follows the same principles but requires a correct connection URI:
- Connection URI:
POSTGRES_URI="postgres://user:password@HOST:5432/memoraweave_db?sslmode=disable"
- Schema Separation:
In the
memoraweave_db, we use three schemas for clean separation:app: Application-owned tables (threads, messages, events).langgraph_ckpt: Reserved for LangGraph internal checkpoints.langgraph_store: Reserved for LangGraph long-term memory.
- Bootstrapping:
You can use the
Query Toolin pgAdmin or run the SQL script viapsqlremotely to initialize the structures. This ensures the application layer and runtime layer stay cleanly separated from the start.
In this phase, we connect the FastAPI backend to our PostgreSQL database using SQLAlchemy with the asyncpg driver. This choice ensures an async end-to-end flow, which is ideal for streaming chat responses and managing multiple concurrent requests.
- Async Engine: Configured in
app/db/session.pyusingcreate_async_engine. - Session Management: An
async_sessionmakerprovides isolated database sessions for each request. - Lifespan Management: The database engine is gracefully disposed of during application shutdown.
- Database Health Check: A new endpoint
/api/v1/health/dballows for connectivity verification.
Ensure your .env file contains the correct DATABASE_URL using the postgresql+asyncpg scheme:
DATABASE_URL=postgresql+asyncpg://user:password@HOST:5432/memoraweave_dbYou can test the database connection by running the server and hitting the following endpoint:
- DB Health Check: http://127.0.0.1:8000/api/v1/health/db
Example Response:
{
"status": "ok",
"database": "connected"
}In this phase, we bridge our database schema to the application layer using SQLAlchemy ORM models and the Repository pattern. This established a robust foundation for thread and message management before moving into LangGraph integration.
- ORM Models: Located in
app/models/, mappingchat_threads,chat_messages, andchat_eventsusing SQLAlchemy 2.0'sMappedsyntax. - Repository Pattern: Encapsulated database logic in
app/repositories/to keep API endpoints clean and maintainable. - Pydantic Schemas: Defined in
app/schemas/for strict request validation. - Thread API: A new router in
app/api/v1/threads.pyprovides CRUD operations for conversations.
You can test the implementation using the Swagger Docs at http://127.0.0.1:8000/docs:
- Create Thread:
POST /api/v1/threadswith auser_idand initialtitle. - Add Message:
POST /api/v1/threads/{thread_id}/messagesto simulate user or assistant inputs. - List history: Use
GETendpoints to retrieve threads by user or messages by thread.
This setup ensures that even as we introduce complex AI logic later, our product history remains a reliable source of truth.
In this phase, we move beyond CRUD operations into a functional chat flow. We introduce a service layer to orchestrate the backend logic and integrate a minimal LangGraph structure for AI responses.
- Service Layer (
app/services/chat_service.py): Centralizes the chat logic—validating threads, persisting messages, and invoking the AI graph. - LLM Factory (
app/llm/factory.py): Uses LangChain'sinit_chat_modelfor provider-agnostic initialization (defaulting to Google Gemini). - LangGraph Integration (
app/graph/): Implements aStateGraphthat processes message history and generates assistant replies. - Chat API: A new endpoint
POST /api/v1/chatthat accepts user input and returns the full conversational turn.
- Request: Client sends
thread_idandmessage. - Persistence: Backend saves the user message to
app.chat_messages. - Inference: The
ChatServiceinvokes the graph, which calls the configured LLM. - Completion: The assistant's reply is automatically saved back to the database.
- Response: Client receives the full turn (user + assistant) for UI update.
Ensure your .env contains:
LLM_PROVIDER="google_genai"LLM_MODEL="gemini-2.5-flash"GOOGLE_API_KEYorGEMINI_API_KEY(required for inference)
POST /api/v1/chat
{
"thread_id": "YOUR_THREAD_UUID",
"user_id": "YOUR_USER_UUID",
"message": "Hello, how can you help me today?"
}In this phase, we implemented persistent short-term memory for the AI agent using LangGraph's PostgreSQL checkpointer. This allows the assistant to maintain context across multiple turns within the same thread_id.
- Persistence Layer: Integrated
langgraph-checkpoint-postgresto store conversational states (checkpoints) in PostgreSQL. - Robust Lifecycle Management: Implemented
AsyncConnectionPoolfrompsycopg_poolto handle checkpointer connections reliably within the FastAPI lifespan. - Multi-turn Orchestration: Updated
ChatServiceto invoke the compiled graph with a persistent checkpointer, enabling the agent to "remember" previous interactions in the same thread. - Separated Configuration: Added dedicated environment variables for the checkpointer URI to support different connection requirements (e.g.,
psycopgvsasyncpg).
Ensure your .env includes the following for the checkpointer:
CHECKPOINTER_DB_URI=postgresql://user:password@HOST:5432/memoraweave_db?sslmode=disable
CHECKPOINTER_AUTO_SETUP=trueTip
Use CHECKPOINTER_AUTO_SETUP=true on the first run to automatically create the necessary langgraph_ckpt tables. You can set it to false afterwards.
- Create a Thread: Use
POST /api/v1/threadsto get a newthread_id. - First Message: Send a message like "My name is Alice" to
POST /api/v1/chat. - Second Message: Send a follow-up like "What is my name?" to the same
thread_id. - Expectation: The assistant should correctly identify you as "Alice", proving that the state was successfully persisted and retrieved.
This milestone ensures that MemoraWeave is no longer just a "stateless" wrapper but a truly context-aware conversational backend.
In this phase, we implemented long-term memory using LangGraph's PostgreSQL Store (AsyncPostgresStore). This allows the assistant to remember user-specific profile information across multiple conversation threads.
- Long-Term Store Layer: Integrated
langgraph.store.postgres.aio.AsyncPostgresStoreto persist cross-thread state. - Context Passing: Introduced
GraphContextto passuser_idnatively into the LangGraph node execution. - Profile Memory Architecture: Added a simplistic rule-based profile extractor to identify a user's name, likes, and bio from messages. The profile is saved in the store and retrieved as context for subsequent queries, regardless of the active thread.
- Dual Memory Concept: The system now seamlessly utilizes two memory layers simultaneously: short-term conversation state (
thread_idvia checkpointer) and long-term user profile context (user_idvia store).
Ensure your .env includes the following for the LangGraph store:
STORE_DB_URI=postgresql://user:password@HOST:5432/memoraweave_db?sslmode=disable
LANGGRAPH_STORE_AUTO_SETUP=true- Create First Thread: Get a
thread_idusingPOST /api/v1/threads. - Provide Profile Info: Send a message like "Nama saya Budi. Saya suka kopi." (My name is Budi. I like coffee.) to
POST /api/v1/chat. The user profile will be extracted and stored. - Create Second Thread: Get a new
thread_idfor the sameuser_id. - Test Cross-Thread Context: In the new thread, ask "Siapa nama saya dan apa yang saya suka?" (What is my name and what do I like?).
- Expectation: The assistant should recall your name and preferences, demonstrating the integration of the long-term memory store across completely different conversation threads.
Building upon the persistent profile store, we have now introduced Semantic Memory powered by vector embeddings and PostgreSQL's vector extension. This enables the assistant to dynamically search and recall past user memories based on the semantic meaning of the user's current input, scoped entirely by user_id.
- Vector Embeddings: Integrated an embedding factory (
app.embeddings) utilizing models like Google'sgemini-embedding-2to convert user memories into high-dimensional vector representations. - Semantic Search via LangGraph Store: Upgraded
AsyncPostgresStoreinitialization to leverageindexconfigurations. We now perform semantic vector similarity search (asearch) on memory namespaces. - Dynamic Candidate Extraction: Implemented a memory extractor (
app.memory.semantic_memory) to automatically identify and isolate episodic or declarative memories from raw user inputs. - Namespace Scoping: All memories are securely namespaced per user (
("memories", str(user_id))) ensuring strict data isolation across conversations and users. - Tri-Layer Memory System: MemoraWeave now leverages three distinct memory paradigms:
- Short-term Thread Memory: Context within a specific conversation (
checkpointer). - Long-term Profile Document: A compact, structured profile of the user (
store.aget). - Long-term Semantic Memory: A vector-searchable database of distinct memories and events (
store.asearch).
- Short-term Thread Memory: Context within a specific conversation (
To support vector embeddings, add the following to your .env:
EMBEDDING_MODEL=gemini-embedding-2
EMBEDDING_DIMENSIONS=768Ensure your PostgreSQL database has the pgvector extension enabled.
Important
Prasyarat pgvector: Ekstensi pgvector harus terinstal di level sistem operasi tempat PostgreSQL berjalan sebelum aplikasi dapat mengaktifkannya.
- Ubuntu/Debian:
sudo apt-get update && sudo apt-get install postgresql-15-pgvector(sesuaikan versi15dengan versi Postgres Anda). - Docker: Gunakan image
pgvector/pgvector:pg15atau versi yang sesuai. - Windows: Download binary
pgvectordan salin ke folderlibdanshare/extensionPostgreSQL Anda.
LangGraph akan mencoba menjalankan CREATE EXTENSION IF NOT EXISTS vector secara otomatis jika STORE_AUTO_SETUP=true, namun ini akan gagal jika file kontrol ekstensi belum ada di sistem.
- Create a Thread: Get a
thread_idusingPOST /api/v1/threads. - Save a Memory: Send a message like "Tahun lalu saya pergi liburan ke Bali dan sangat menyukai pantainya." to
POST /api/v1/chat. The system will extract this as a distinct memory candidate, embed it, and save it to the vector store. - Create a New Thread: Get a new
thread_idfor the sameuser_id. - Recall the Memory Semantically: In the new thread, ask "Apakah kamu ingat ke mana saya pergi liburan tahun lalu?".
- Expectation: The assistant will perform a vector search, retrieve the semantic memory about your trip to Bali, inject it into the prompt, and accurately answer your question despite it being a completely new conversation thread.
As the system scales, handling concurrent requests correctly becomes crucial. In Phase 8A, we addressed two primary reliability challenges:
- Concurrent User Messages: Preventing race conditions when a user sends multiple messages rapidly in the same thread.
- Client Retries: Preventing duplicate messages and wasted LLM calls when a client retries a request due to network timeouts but the server actually succeeded.
- Idempotency Table (
app.chat_requests): Introduced a new table to track the state of incoming requests (started,succeeded,failed) based on a uniqueIdempotency-Keyprovided by the client. - Request Hashing: Validates that if a retry occurs with the same
Idempotency-Key, the request payload (thread_id,user_id,message) must perfectly match the original request. - Transaction-Level Advisory Locks: Implemented a thread-level lock (
pg_advisory_xact_lockviaThreadLockRepository) to ensure only one chat request is processed for a giventhread_idat any time. - Replay Responses: If a retry hits the server and the previous attempt with the same idempotency key already succeeded, the server intercepts it and directly returns the cached
response_jsonwithout re-running LangGraph.
- The endpoint
POST /api/v1/chatnow requires theIdempotency-Keyheader.
During database schema evolution, it is common to encounter issues with Docker's initialization scripts. Here are important guidelines and troubleshooting steps:
The Problem:
PostgreSQL's Docker image only executes scripts inside /docker-entrypoint-initdb.d (like 001_init_app_chat.sql or 002_chat_request_idempotency.sql) once, when the data volume (postgres_data) is empty. If you add a new SQL file after the database has been created, Docker will skip it upon restart, leading to missing tables (e.g., relation "app.chat_requests" does not exist).
Solutions:
-
Reset the database (Development Only): If data loss is acceptable, you can completely rebuild the database so all init scripts run again:
docker compose down -v docker compose up -d
-
Run new SQL scripts manually (Preserve Data): If you want to keep existing data, execute the new SQL file manually inside the running container. Important: If you are using Git Bash on Windows, you must prepend
MSYS_NO_PATHCONV=1to prevent path translation errors.MSYS_NO_PATHCONV=1 docker exec -it memoraweave_postgres psql -U mlflow -d memoraweave_db -f /docker-entrypoint-initdb.d/002_chat_request_idempotency.sql -
Long-Term Recommendation: For production environments, do not rely on
docker-entrypoint-initdb.dfor ongoing schema changes. Implement a migration tool like Alembic to safely manage schema evolutions (creating new tables, adding columns) over time.
Adding Docker Healthchecks:
It is highly recommended to add a healthcheck to your PostgreSQL service in docker-compose.yml to ensure other dependent services wait until the database is fully ready to accept connections. We have updated our docker-compose.yml to include a healthcheck.
In this phase, we enhanced the reliability of the ChatService by properly handling and auditing errors, and we introduced automated testing using pytest to ensure core flows remain stable.
- Error Auditing: When LangGraph or the LLM model encounters an error, the system now:
- Marks the idempotency request in
app.chat_requestsasfailed. - Logs a structured
chat_errorevent inapp.chat_eventsfor debugging and UI error reporting.
- Marks the idempotency request in
- Structured Exceptions: Replaced generic exceptions with specific domain errors (e.g.,
ThreadNotFoundError,IdempotencyConflictError,RequestPreviouslyFailedError,ChatProcessingError) to make API responses more predictable. - Fake Graph for Testing: Created a
FakeSuccessGraphandFakeFailGraph(tests/fakes.py) to simulate AI responses. This ensures unit tests are fast, deterministic, and don't consume real LLM API credits. - Pytest Integration: Set up
pytestwithpytest.mark.anyioto test asynchronous code. The minimal test suite now verifies the success flow, idempotency logic, and failure auditing.
To run the test suite and verify the service logic without hitting external APIs:
pytest -qExpected Outcome: You should see all tests pass successfully, confirming that the success, idempotency, and failure flows are working as expected.