Objective
A personal assistant has to remember you (preferences, constraints), route your request to the right capability (add a reminder vs. answer a question), look things up in your own notes (RAG), and reply grounded in all of it. That's the long-term-memory, tool-routing, and RAG building blocks working together. Here you'll assemble them into one assistant on one database — no vector store, no cache, no router service. The same brain drives any framework or a voice agent — see Use it from your agent at the end.
Step 1: Create the assistant's long-term memory
Durable facts about the user, embedded for recall and weighted by importance.
CREATE TABLE IF NOT EXISTS recipe_pa_memory (
memory_id INTEGER PRIMARY KEY,
content TEXT,
importance DOUBLE,
embedding VECTOR(384)
);
INSERT INTO recipe_pa_memory (memory_id, content, importance) VALUES
(1,'The user is vegetarian.',0.95),
(2,'The user prefers meetings after 10am.',0.70),
(3,'The user is training for a half marathon in October.',0.75),
(4,'The user dislikes long emails; keep replies short.',0.80),
(5,'The user lives in Lisbon (WET timezone).',0.85);
UPDATE recipe_pa_memory SET embedding = EMBED(content);
Step 2: Create the assistant's tool registry
The capabilities the assistant can invoke, described in natural language for semantic routing.
CREATE TABLE IF NOT EXISTS recipe_pa_tools (
tool_id INTEGER PRIMARY KEY,
tool_name TEXT,
description TEXT,
embedding VECTOR(384)
);
INSERT INTO recipe_pa_tools (tool_id, tool_name, description) VALUES
(1,'add_reminder','Create a reminder or to-do item for a specific time or date.'),
(2,'schedule_meeting','Find a time and book a calendar meeting with someone.'),
(3,'search_notes','Search the user''s personal notes and documents for an answer.'),
(4,'send_message','Compose and send a short message or email on the user''s behalf.'),
(5,'check_weather','Look up the current or forecast weather for a location.');
UPDATE recipe_pa_tools SET embedding = EMBED(description);
Step 3: Create the user's notes (for RAG)
Personal knowledge the assistant can ground answers in.
CREATE TABLE IF NOT EXISTS recipe_pa_notes (
note_id INTEGER PRIMARY KEY,
content TEXT,
embedding VECTOR(384)
);
INSERT INTO recipe_pa_notes (note_id, content) VALUES
(1,'My passport expires in March next year — renew it before booking the Japan trip.'),
(2,'The half-marathon plan: long run every Sunday, rest on Mondays.'),
(3,'Favorite vegetarian place in Lisbon is Ao 26 in Chiado.'),
(4,'Dentist appointment is the second Tuesday of every month.');
UPDATE recipe_pa_notes SET embedding = EMBED(content);
Step 4: Route the request to the right tool
The user says "remind me to renew my passport" — route it by meaning to the reminder tool.
SELECT tool_name,
COSINE_SIMILARITY(embedding, EMBED('remind me to renew my passport next month')) AS match_score
FROM recipe_pa_tools
ORDER BY match_score DESC
LIMIT 1;
Step 5: Recall the relevant memory for personalization
Pull the durable facts that should shape the reply — blending relevance and importance.
SELECT content,
COSINE_SIMILARITY(embedding, EMBED('suggest where to eat dinner tonight')) * 0.7 + importance * 0.3 AS score
FROM recipe_pa_memory
ORDER BY score DESC
LIMIT 2;
Step 6: Look up an answer in the user's notes (RAG)
For a question, retrieve the most relevant personal note.
SELECT content,
COSINE_SIMILARITY(embedding, EMBED('where do I like to eat in Lisbon?')) AS relevance
FROM recipe_pa_notes
ORDER BY relevance DESC
LIMIT 1;
Step 7: Produce a grounded, personalized reply (GENERATE)
Combine memory + the retrieved note into a short reply that respects the user's preferences. First materialize the top user fact and the most relevant note into a single context row (projecting the scores we order by), then generate from that row.
CREATE TABLE IF NOT EXISTS recipe_pa_fact (memory_id INTEGER PRIMARY KEY, content TEXT, importance DOUBLE);
INSERT INTO recipe_pa_fact (memory_id, content, importance)
SELECT memory_id, content, importance FROM recipe_pa_memory ORDER BY importance DESC LIMIT 1;
CREATE TABLE IF NOT EXISTS recipe_pa_note (note_id INTEGER PRIMARY KEY, content TEXT, relevance DOUBLE);
INSERT INTO recipe_pa_note (note_id, content, relevance)
SELECT note_id, content,
COSINE_SIMILARITY(embedding, EMBED('dinner recommendation in Lisbon')) AS relevance
FROM recipe_pa_notes ORDER BY relevance DESC LIMIT 1;
CREATE TABLE IF NOT EXISTS recipe_pa_ctx (id INTEGER PRIMARY KEY, fact TEXT, note TEXT);
INSERT INTO recipe_pa_ctx (id, fact, note)
SELECT 1,
(SELECT content FROM recipe_pa_fact LIMIT 1),
(SELECT content FROM recipe_pa_note LIMIT 1);
SELECT GENERATE(
'You are a concise personal assistant. User facts: ' || fact ||
' Relevant note: ' || note ||
' Request: Recommend somewhere for dinner tonight. Reply in one short sentence.') AS reply
FROM recipe_pa_ctx;
Cleanup (Optional)
DROP TABLE IF EXISTS recipe_pa_memory;
DROP TABLE IF EXISTS recipe_pa_tools;
DROP TABLE IF EXISTS recipe_pa_notes;
DROP TABLE IF EXISTS recipe_pa_fact;
DROP TABLE IF EXISTS recipe_pa_note;
DROP TABLE IF EXISTS recipe_pa_ctx;
Expected Outcomes
- Step 4 routes "remind me to renew my passport" to add_reminder by meaning.
- Step 5 surfaces the vegetarian preference (high importance) for a dinner request.
- Step 6 retrieves the "favorite vegetarian place is Ao 26" note.
- Step 7 returns a one-sentence dinner recommendation that's both grounded in the note and respects the vegetarian preference — memory + tools + RAG in one reply.
You've built a personal assistant — long-term memory, semantic tool routing, and RAG over personal notes — on one database.
Use it from your agent (framework-agnostic — this is the whole point)
The assistant brain is just memory + a tool registry + notes, all queried the same way, so any agent shell drives it with no framework lock-in:
- REST / SDK —
POST /v1/query/execute(any language), or@synapcores/sdkclient.executeQuery(...). Per turn your agent routes (Step 4), recalls memory (Step 5), runs RAG over notes (Step 6), and replies (Step 7); when the route is an action tool, it invokes that function instead. - MCP (native, on by default) — point any MCP client (Claude Code, Cursor, a custom loop, a voice runtime) at
ws://<your-instance>/mcp?token=<jwt>(JWT from onePOST /v1/auth/login→access_token). Thequerytool routes/recalls/retrieves; theexecutetool writes new memories and notes — the assistant loop as tool calls. - Any framework — OpenClaw, a LangGraph assistant, a custom loop, or a voice assistant on a phone or smart speaker all call the same brain. The database is the brain; the framework is swappable.
Key Concepts Learned
- A personal assistant composes long-term memory, semantic tool routing, and RAG over personal notes.
- Routing decides what to do; memory + RAG decide what to say — all from the same query surface.
- Blending importance into memory recall keeps high-stakes facts (allergies, constraints) front and center.
- Because it's plain data ops (SQL + GENERATE / REST / MCP), the assistant works from any framework — the agent-agnostic backend pattern this cluster builds on.