- Create /docs structure (microdao, daarion, agents) - Organize 61 cursor technical docs - Add README files for each category - Copy key documents to public categories - Add GitHub setup instructions and scripts
19 KiB
13 — Agent Memory System (MicroDAO)
Цей документ описує архітектуру памʼяті агентів у MicroDAO:
-
short-term, mid-term, long-term;
-
персональна / командна / глобальна памʼять;
-
Co-Memory та RAG;
-
як памʼять інтегрується з Agent Runtime Core (12);
-
як це використовувати для еволюційного агента (09).
1. Цілі системи памʼяті
-
Зробити агентів контекстними: вони памʼятають діалоги, рішення, факти.
-
Розділити памʼять за часом і рівнем узагальнення:
-
short-term → останні репліки;
-
mid-term → сесії / таски / важливі обговорення;
-
long-term → узагальнені знання про команду/проєкт.
-
-
Дати можливість:
-
переглядати памʼять,
-
очищати її,
-
контролювати, що саме зберігається.
-
-
Готувати основу для DAGI та Train-to-Earn (агрегована колективна памʼять).
2. Рівні памʼяті
2.1. Short-Term Memory (STM)
-
Останні N повідомлень (user ↔ агент) в поточному контексті (канал / чат).
-
Зберігається як
AgentMessage(див. 12_agent_runtime_core.md). -
Використовується в кожному запиті до LLM.
Приклад:
-
останні 20–50 повідомлень у каналі;
-
спеціальні system-репліки (актуальні інструкції).
2.2. Mid-Term Memory (MTM)
-
Важливі фрагменти діалогів, завдання, рішення, які стосуються:
-
конкретних тасок,
-
спринтів,
-
обговорень проєктів.
-
-
Може бути збережена як:
-
підсумки сесій,
-
«замітки агента»,
-
структуровані записи (JSON).
-
Використання:
-
контекст для агентських звітів,
-
нагадування про те, що команда домовилася зробити.
2.3. Long-Term Memory (LTM)
-
Узагальнені факти про:
-
команду,
-
проєкти,
-
стилі роботи,
-
правила,
-
терміни та словник.
-
Формат:
-
списки фактів (текстові),
-
векторні ембедінги (для RAG).
Приклади фактів:
-
«Наш основний продукт — MicroDAO, ми фокусуємося на невеликих спільнотах.»
-
«Для терміну "DAGI" ми маємо окремий опис, який завжди треба враховувати.»
3. Простір памʼяті (Scopes)
Памʼять розділяється за обсягом:
-
Personal
- пов'язана з конкретним користувачем (Personal Agent).
-
Channel
- стосується конкретного каналу, де агент працює.
-
Team (microDAO)
- загальна памʼять всієї спільноти.
-
Global / DAGI
- узагальнені патерни, які можуть бути анонімізовано експортовані.
4. Модель даних
Таблиці (логічно):
-
agent_memory_events-
id
-
agent_id
-
team_id
-
channel_id (optional)
-
user_id (optional)
-
scope:
short_term | mid_term | long_term -
kind:
message | fact | summary | note -
body: text/json
-
created_at
-
-
agent_memory_facts_vector-
id
-
team_id
-
agent_id
-
fact_text
-
embedding (vector)
-
metadata (json)
-
-
agent_memory_snapshots(опціонально)- агреговані snapshot-и стану памʼяті.
5. AgentMemoryAdapter (деталізація)
Посилання на 12_agent_runtime_core.md:
export interface AgentMemoryAdapter {
loadShortTerm(ctx: AgentContext): Promise<AgentMessage[]>;
loadLongTerm(ctx: AgentContext): Promise<string[]>;
saveTurn(ctx: AgentContext, turn: AgentMessage): Promise<void>;
appendFact(ctx: AgentContext, fact: string): Promise<void>;
}
5.1. loadShortTerm
-
Витягує останні
Nподій типуkind = 'message'зі scopeshort_termдля:-
agent_id, -
team_id, -
channel_id(якщо є).
-
5.2. loadLongTerm
- Витягує список текстових фактів зі scope
long_term(черезagent_memory_eventsзkind = 'fact').
5.3. saveTurn
-
Записує повідомлення user/assistant як
message(short-term). -
Якщо увімкнено автоматичне ущільнення памʼяті — може переносити деякі фрагменти в mid-term.
5.4. appendFact
-
Додає факт у long-term (як
kind = 'fact'). -
Додатково:
-
рахує ембедінг (через окремий LLM/embedding API),
-
зберігає в
agent_memory_facts_vector.
-
6. RAG (Retrieval-Augmented Generation)
6.1. Retrieval
Коли агент отримує новий запит, перед викликом LLM:
-
Формує пошуковий запит (query) з тексту user.
-
Шукає релевантні факти у:
-
agent_memory_facts_vector, -
(опційно) Co-Memory документів (файли, wiki).
-
-
Обмежує контекст, наприклад Top-K = 5–10 фактів.
6.2. Включення в промпт
Факти додаються в LONG_TERM_MEMORY (див. 12_agent_runtime_core.md):
const memoryMsg: AgentMessage = {
role: "system",
content:
"LONG_TERM_MEMORY:\n" +
retrievedFacts.map((f, i) => `- ${f.text}`).join("\n"),
};
7. Перетікання памʼяті (compression / distillation)
Щоб памʼять не перетворювалась на хаос, потрібні періодичні "distillation jobs".
7.1. Distillation Job
Раз на N повідомлень або раз на день для команди:
-
Беремо всі short-term повідомлення за певний період.
-
Feed-имо їх у Meta-Agent (див. 09_evolutionary_agent.md).
-
Отримуємо:
-
конспект (summary),
-
витяг корисних фактів,
-
пропозиції правил.
-
-
Записуємо:
-
summary → mid-term,
-
факти → long-term (appendFact),
-
пропозиції → evolution suggestions.
-
7.2. Видалення шуму
Після успішної дистиляції:
-
можна частину короткої памʼяті чистити;
-
можна перевести непотрібні
messageу архів.
8. Контроль з боку користувача
У UI потрібно дати користувачу можливість:
-
Переглядати памʼять (принаймні long-term):
-
список фактів,
-
розділений по каналах / темах.
-
-
Видаляти факти:
-
для конфіденційних даних,
-
при помилках.
-
-
Вимикати зберігання:
- «Не зберігати DM-переписку з агентом у довгострокову памʼять».
-
Експортувати памʼять:
- для аудиту / переносу.
9. Memory Scopes vs Agent Roles
Guide Agent (онбординг)
-
short-term: поточна сесія онбордингу;
-
long-term: факти про те, як виглядає створена команда (не обовʼязково).
Team Assistant
-
short-term: останні діалоги в конкретному каналі;
-
mid-term: summaries мітингів / сесій;
-
long-term: знання про команду, процеси, словник.
Meta-Agent
-
працює на mid-/long-term даних:
-
аналізує їх,
-
пропонує зміни в правилах,
-
оновлює памʼять.
-
10. Псевдокод реалізації Adapter'а
export class PgAgentMemoryAdapter implements AgentMemoryAdapter {
async loadShortTerm(ctx: AgentContext): Promise<AgentMessage[]> {
const rows = await db.agent_memory_events.findMany({
where: {
agent_id: ctx.agent.id,
team_id: ctx.teamId,
channel_id: ctx.channelId ?? null,
scope: "short_term",
kind: "message",
},
orderBy: { created_at: "desc" },
limit: 50,
});
return rows.reverse().map(rowToMessage);
}
async loadLongTerm(ctx: AgentContext): Promise<string[]> {
const rows = await db.agent_memory_events.findMany({
where: {
agent_id: ctx.agent.id,
team_id: ctx.teamId,
scope: "long_term",
kind: "fact",
},
orderBy: { created_at: "desc" },
limit: 100,
});
return rows.map(r => r.body_text);
}
async saveTurn(ctx: AgentContext, turn: AgentMessage): Promise<void> {
await db.agent_memory_events.insert({
agent_id: ctx.agent.id,
team_id: ctx.teamId,
channel_id: ctx.channelId ?? null,
scope: "short_term",
kind: "message",
body_json: turn,
});
}
async appendFact(ctx: AgentContext, fact: string): Promise<void> {
await db.agent_memory_events.insert({
agent_id: ctx.agent.id,
team_id: ctx.teamId,
scope: "long_term",
kind: "fact",
body_text: fact,
});
// TODO: обчислити embedding та зберегти у agent_memory_facts_vector
}
}
11. RAG Implementation
11.1. Embedding Generation
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
});
export async function generateEmbedding(text: string): Promise<number[]> {
const result = await embeddings.embedQuery(text);
return result;
}
11.2. Vector Search
export async function searchRelevantFacts(
query: string,
agentId: string,
teamId: string,
topK: number = 5
): Promise<Array<{ text: string; score: number }>> {
// Генеруємо embedding для запиту
const queryEmbedding = await generateEmbedding(query);
// Шукаємо найближчі вектори (cosine similarity)
const results = await db.$queryRaw`
SELECT
fact_text,
1 - (embedding <=> ${queryEmbedding}::vector) as similarity
FROM agent_memory_facts_vector
WHERE agent_id = ${agentId}
AND team_id = ${teamId}
ORDER BY similarity DESC
LIMIT ${topK}
`;
return results.map(r => ({
text: r.fact_text,
score: r.similarity,
}));
}
11.3. Integration with runAgentTurn
export async function runAgentTurn(ctx: AgentContext): Promise<AgentTurnResult> {
// 1. Завантажуємо short-term пам'ять
const shortTerm = await ctx.memory.loadShortTerm(ctx);
// 2. RAG: шукаємо релевантні факти
const relevantFacts = await searchRelevantFacts(
ctx.input,
ctx.agent.id,
ctx.teamId,
5
);
// 3. Завантажуємо long-term (статичні факти)
const longTerm = await ctx.memory.loadLongTerm(ctx);
// 4. Об'єднуємо RAG-результати з long-term
const allFacts = [
...relevantFacts.map(f => f.text),
...longTerm,
];
// 5. Готуємо повідомлення для LLM
const messages = buildLLMMessages(ctx, shortTerm, allFacts);
// ... решта логіки
}
12. Distillation Job Implementation
export async function runDistillationJob(
agentId: string,
teamId: string,
period: { from: Date; to: Date }
): Promise<void> {
// 1. Збираємо всі short-term повідомлення за період
const messages = await db.agent_memory_events.findMany({
where: {
agent_id: agentId,
team_id: teamId,
scope: "short_term",
kind: "message",
created_at: {
gte: period.from,
lte: period.to,
},
},
orderBy: { created_at: "asc" },
});
// 2. Формуємо контекст для Meta-Agent
const conversationLog = messages.map(m => ({
role: m.body_json.role,
content: m.body_json.content,
timestamp: m.created_at,
}));
// 3. Викликаємо Meta-Agent для аналізу
const metaAgent = await getMetaAgent(agentId);
const analysis = await metaAgent.analyze(conversationLog);
// 4. Зберігаємо результати
if (analysis.summary) {
await db.agent_memory_events.create({
data: {
agent_id: agentId,
team_id: teamId,
scope: "mid_term",
kind: "summary",
body_text: analysis.summary,
},
});
}
if (analysis.facts && analysis.facts.length > 0) {
for (const fact of analysis.facts) {
await db.agent_memory_events.create({
data: {
agent_id: agentId,
team_id: teamId,
scope: "long_term",
kind: "fact",
body_text: fact,
},
});
// Генеруємо embedding та зберігаємо
const embedding = await generateEmbedding(fact);
await db.agent_memory_facts_vector.create({
data: {
agent_id: agentId,
team_id: teamId,
fact_text: fact,
embedding: embedding,
},
});
}
}
// 5. Очищаємо оброблені short-term повідомлення
await db.agent_memory_events.deleteMany({
where: {
agent_id: agentId,
team_id: teamId,
scope: "short_term",
kind: "message",
created_at: {
gte: period.from,
lte: period.to,
},
},
});
}
13. Database Schema
13.1. agent_memory_events
CREATE TABLE agent_memory_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
agent_id UUID NOT NULL REFERENCES agents(id),
team_id UUID NOT NULL REFERENCES teams(id),
channel_id UUID REFERENCES channels(id),
user_id UUID REFERENCES users(id),
scope TEXT NOT NULL CHECK (scope IN ('short_term', 'mid_term', 'long_term')),
kind TEXT NOT NULL CHECK (kind IN ('message', 'fact', 'summary', 'note')),
body_text TEXT,
body_json JSONB,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
INDEX idx_agent_team_scope (agent_id, team_id, scope),
INDEX idx_agent_channel (agent_id, channel_id),
INDEX idx_created_at (created_at)
);
13.2. agent_memory_facts_vector
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE agent_memory_facts_vector (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
agent_id UUID NOT NULL REFERENCES agents(id),
team_id UUID NOT NULL REFERENCES teams(id),
fact_text TEXT NOT NULL,
embedding vector(1536), -- OpenAI ada-002 embedding size
metadata JSONB,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
INDEX idx_agent_team (agent_id, team_id),
INDEX idx_embedding USING ivfflat (embedding vector_cosine_ops)
);
14. API Endpoints
14.1. GET /agents/{id}/memory
export async function getAgentMemory(req: Request, res: Response) {
const { agentId } = req.params;
const { scope, limit = 50 } = req.query;
const memory = await db.agent_memory_events.findMany({
where: {
agent_id: agentId,
scope: scope as string,
},
orderBy: { created_at: "desc" },
take: parseInt(limit as string),
});
res.json({
scope,
items: memory,
});
}
14.2. DELETE /agents/{id}/memory/{memoryId}
export async function deleteMemoryItem(req: Request, res: Response) {
const { agentId, memoryId } = req.params;
await db.agent_memory_events.delete({
where: {
id: memoryId,
agent_id: agentId,
},
});
res.json({ success: true });
}
14.3. POST /agents/{id}/memory/distill
export async function triggerDistillation(req: Request, res: Response) {
const { agentId } = req.params;
const { days = 7 } = req.body;
const from = new Date();
from.setDate(from.getDate() - days);
await runDistillationJob(agentId, req.teamId, {
from,
to: new Date(),
});
res.json({ success: true });
}
15. Інтеграція з еволюційним агентом (09)
Еволюційний агент:
-
читає
agent_memory_events(особливо з негативним фідбеком), -
агрегує логи,
-
робить distillation,
-
створює пропозиції покращень.
Memory System → джерело для:
-
аналізу діалогів,
-
виявлення патернів,
-
побудови Train-to-Earn.
16. Тестування
16.1. Unit Tests
describe("PgAgentMemoryAdapter", () => {
it("should load short-term memory", async () => {
const adapter = new PgAgentMemoryAdapter();
const ctx = createMockContext();
const messages = await adapter.loadShortTerm(ctx);
expect(messages).toBeInstanceOf(Array);
expect(messages.length).toBeLessThanOrEqual(50);
});
it("should save turn to memory", async () => {
const adapter = new PgAgentMemoryAdapter();
const ctx = createMockContext();
const turn: AgentMessage = {
role: "user",
content: "Test message",
};
await adapter.saveTurn(ctx, turn);
const messages = await adapter.loadShortTerm(ctx);
expect(messages).toContainEqual(
expect.objectContaining({ content: "Test message" })
);
});
});
17. Завдання для Cursor
Приклад промта:
You are a senior backend engineer.
Implement the Agent Memory System for MicroDAO using:
- 13_agent_memory_system.md
- 12_agent_runtime_core.md
- 11_llm_integration.md
- 09_evolutionary_agent.md
- 05_coding_standards.md
Tasks:
1) Create tables: agent_memory_events, agent_memory_facts_vector.
2) Implement PgAgentMemoryAdapter with short-term + long-term.
3) Wire PgAgentMemoryAdapter into Agent Runtime Core.
4) Add a simple RAG retrieval step using facts.
5) Expose a debug endpoint to inspect agent memory (GET /agents/{id}/memory).
Output:
- list of modified files
- diff
- summary
18. Результат
Після впровадження цієї системи:
-
агенти MicroDAO мають справжню багаторівневу памʼять;
-
можна керувати тим, що саме вони памʼятають;
-
можна будувати RAG, еволюційний аналіз, Train-to-Earn;
-
перехід до DAGI стає природним — через спільну колективну памʼять агентів.
Готово.
Це повна специфікація системи пам'яті агентів, готова до використання в Cursor.