SELF LEARNING ENHANCEMENTS
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
🧠 AI Agent Task System - Self-Learning Enhancements
The Problem We're Solving
Limited Context + No Memory = Groundhog Day AI
Every AI session starts fresh, forgetting:
- What worked before
- What didn't work
- Patterns that led to success
- User preferences and project conventions
Current state: Infrastructure exists, but learning loop is broken
🎯 Vision: World-Class Self-Learning AI
┌────────────────────────────────────────────────────────────────────────────┐
│ INTELLIGENT AGENT MEMORY SYSTEM │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ EPISODIC │ │ SEMANTIC │ │ PROCEDURAL │ │
│ │ MEMORY │ │ MEMORY │ │ MEMORY │ │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
│ │ What happened │ │ General facts │ │ How to do │ │
│ │ in sessions │ │ and knowledge │ │ things well │ │
│ │ (decisions) │ │ (patterns) │ │ (successful │ │
│ │ │ │ │ │ patterns) │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ └──────────┬──────────┴──────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ UNIFIED CONTEXT ENGINE │ │
│ │ • Vector-based retrieval (RAG) │ │
│ │ • Smart compression & prioritization │ │
│ │ • Cross-task knowledge transfer │ │
│ └────────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ AI AGENT SESSION │ │
│ │ • Receives optimized context │ │
│ │ • Logs decisions with reasoning │ │
│ │ • Gets feedback → feeds back │ │
│ └─────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
🚀 Enhancement Roadmap
Phase 1: Vector Memory & RAG (HIGH PRIORITY)
Problem: Context compression loses semantic relationships. A decision about "authentication" 6 months ago might be highly relevant today but gets pruned.
Solution: Embed decisions and retrieve by semantic similarity.
// New: agent-vector-memory.service.ts
interface EmbeddedDecision {
id: string;
taskId: string;
decisionId: string;
// The decision content
question: string;
chosen: string;
reasoning: string;
// Vector embedding (1536 dims for OpenAI, 1024 for Cohere)
embedding: number[];
// Metadata for filtering
taskType: AgentTaskType;
agentType: AgentType;
timestamp: Date;
// Outcome data (populated after feedback)
qualityRating?: number;
wasSuccessful?: boolean;
userOverride?: boolean;
}
class AgentVectorMemoryService {
/**
* Embed a decision and store for future retrieval
*/
async embedAndStore(decision: AgentDecision, taskContext: TaskContext): Promise<void> {
// Generate embedding using AI
const text = `Question: ${decision.question}\nChosen: ${decision.chosen}\nReasoning: ${decision.reasoning}`;
const embedding = await this.aiService.generateEmbedding(text);
await this.vectorStore.insert({
...decision,
embedding,
taskType: taskContext.type,
agentType: decision.agentType,
timestamp: new Date()
});
}
/**
* Find similar past decisions for a new question
* This is the key innovation - semantic retrieval of relevant past experience
*/
async findSimilarDecisions(
currentQuestion: string,
options: {
limit?: number;
minSimilarity?: number;
filterByTaskType?: AgentTaskType;
filterByQualityRating?: number; // Only get high-rated decisions
filterBySuccess?: boolean;
} = {}
): Promise<SimilarDecision[]> {
const queryEmbedding = await this.aiService.generateEmbedding(currentQuestion);
return this.vectorStore.similaritySearch({
vector: queryEmbedding,
limit: options.limit || 5,
minSimilarity: options.minSimilarity || 0.7,
filter: {
qualityRating: { $gte: options.filterByQualityRating || 3 },
wasSuccessful: options.filterBySuccess !== false,
...(options.filterByTaskType && { taskType: options.filterByTaskType })
}
});
}
/**
* Update decision outcome after user feedback
* This closes the learning loop!
*/
async updateDecisionOutcome(
decisionId: string,
outcome: { qualityRating: number; wasSuccessful: boolean; userOverride?: boolean }
): Promise<void> {
await this.vectorStore.update(decisionId, {
qualityRating: outcome.qualityRating,
wasSuccessful: outcome.wasSuccessful,
userOverride: outcome.userOverride
});
}
}
MongoDB Atlas Vector Search Configuration:
{
"mappings": {
"dynamic": false,
"fields": {
"embedding": {
"type": "knnVector",
"dimensions": 1536,
"similarity": "cosine"
},
"qualityRating": { "type": "number" },
"taskType": { "type": "string" },
"agentType": { "type": "string" },
"wasSuccessful": { "type": "boolean" }
}
}
}
Phase 2: Outcome Correlation Engine
Problem: We log decisions but never correlate them with outcomes. A decision made with 90% confidence that led to a 2/5 rating should inform future confidence scoring.
Solution: Build an outcome correlation system.
// New: agent-outcome-correlation.service.ts
interface DecisionOutcomeCorrelation {
decisionId: string;
predictedConfidence: number; // What AI said
actualOutcome: number; // What user rated (1-5 normalized to 0-1)
confidenceCalibration: number; // predicted - actual
decisionType: DecisionType;
agentType: AgentType;
reasoning: string;
}
class AgentOutcomeCorrelationService {
/**
* When user submits feedback, correlate with all decisions in that task
*/
async correlateOutcomes(taskId: string, feedback: LearningFeedback): Promise<void> {
const task = await this.taskService.getTask(taskId);
const normalizedRating = feedback.qualityRating / 5; // 0-1 scale
for (const session of task.sessions) {
for (const decision of session.decisionsLog) {
const correlation: DecisionOutcomeCorrelation = {
decisionId: decision.id,
predictedConfidence: decision.confidence,
actualOutcome: normalizedRating,
confidenceCalibration: decision.confidence - normalizedRating,
decisionType: decision.type,
agentType: session.agentType,
reasoning: decision.reasoning
};
await this.store(correlation);
await this.vectorMemory.updateDecisionOutcome(decision.id, {
qualityRating: feedback.qualityRating,
wasSuccessful: feedback.overallSuccess,
userOverride: feedback.wasModified
});
}
}
// Recalculate confidence calibration for this decision type
await this.recalibrateConfidence(task.type);
}
/**
* Get calibrated confidence for a new decision
* If historical decisions of this type were overconfident, adjust down
*/
async getCalibratedConfidence(
rawConfidence: number,
decisionType: DecisionType,
agentType: AgentType
): Promise<number> {
const historicalCalibration = await this.getAverageCalibration(decisionType, agentType);
// If historical average was +0.2 (overconfident), reduce by 0.2
const calibratedConfidence = rawConfidence - historicalCalibration;
return Math.max(0, Math.min(1, calibratedConfidence));
}
/**
* Generate a report on decision quality by type
*/
async generateQualityReport(
filters?: { taskType?: AgentTaskType; agentType?: AgentType; dateRange?: DateRange }
): Promise<QualityReport> {
const correlations = await this.getCorrelations(filters);
return {
byDecisionType: this.aggregateByDecisionType(correlations),
byAgentType: this.aggregateByAgentType(correlations),
overallCalibration: this.calculateOverallCalibration(correlations),
topPerformingPatterns: this.findTopPatterns(correlations),
underperformingPatterns: this.findUnderperformingPatterns(correlations)
};
}
}
Phase 3: Pattern Mining & Prompt Improvement
Problem: High-quality decisions exist in the database but aren't used to improve future prompts.
Solution: Automatically mine patterns and inject into prompts.
// New: agent-pattern-mining.service.ts
interface LearnedPattern {
id: string;
description: string;
// Pattern details
decisionType: DecisionType;
context: string; // Abstracted context (e.g., "when building UI components")
recommendation: string; // What to do
reasoning: string; // Why it works
// Evidence
exampleDecisionIds: string[];
supportCount: number; // How many times this pattern led to success
successRate: number; // % of times this led to good outcomes
avgQualityRating: number;
// Metadata
agentTypes: AgentType[]; // Which agents this applies to
taskTypes: AgentTaskType[];
createdAt: Date;
updatedAt: Date;
}
class AgentPatternMiningService {
/**
* Mine patterns from high-quality decisions
* Run periodically (e.g., daily) to discover new patterns
*/
async minePatterns(): Promise<LearnedPattern[]> {
// Get all high-quality decisions (4+ rating)
const highQualityDecisions = await this.vectorMemory.query({
filter: { qualityRating: { $gte: 4 } },
limit: 1000
});
// Cluster similar decisions
const clusters = await this.clusterDecisions(highQualityDecisions);
// Extract patterns from each cluster
const patterns: LearnedPattern[] = [];
for (const cluster of clusters) {
if (cluster.size >= 3) { // Need at least 3 examples
const pattern = await this.extractPattern(cluster);
if (pattern.successRate >= 0.8) { // 80%+ success rate
patterns.push(pattern);
}
}
}
// Store patterns
await this.storePatterns(patterns);
return patterns;
}
/**
* Use AI to extract a generalized pattern from similar decisions
*/
private async extractPattern(cluster: DecisionCluster): Promise<LearnedPattern> {
const prompt = `Analyze these ${cluster.size} similar high-quality AI decisions and extract a general pattern:
${cluster.decisions.map(d => `
Question: ${d.question}
Chosen: ${d.chosen}
Reasoning: ${d.reasoning}
Quality Rating: ${d.qualityRating}/5
`).join('\n---\n')}
Extract:
1. A general description of when this pattern applies
2. The recommended approach
3. Why this approach works
4. What types of tasks/agents this applies to
Format as JSON.`;
const response = await this.aiService.generate(prompt);
return JSON.parse(response);
}
/**
* Get relevant patterns for a new task
* These get injected into the AI prompt
*/
async getPatternsForTask(
taskType: AgentTaskType,
agentType: AgentType,
taskGoal: string
): Promise<LearnedPattern[]> {
// Get patterns matching task/agent type
const typePatterns = await this.getPatternsByType(taskType, agentType);
// Also get semantically similar patterns
const semanticPatterns = await this.getSemanticallySimilarPatterns(taskGoal);
// Merge and rank by relevance
const allPatterns = [...typePatterns, ...semanticPatterns];
const uniquePatterns = this.deduplicatePatterns(allPatterns);
return uniquePatterns
.sort((a, b) => b.successRate - a.successRate)
.slice(0, 5); // Top 5 most relevant patterns
}
/**
* Generate few-shot examples from patterns for prompt injection
*/
generateFewShotExamples(patterns: LearnedPattern[]): string {
return patterns.map(p => `
### Learned Pattern: ${p.description}
When: ${p.context}
Approach: ${p.recommendation}
Why: ${p.reasoning}
Success Rate: ${(p.successRate * 100).toFixed(0)}%
`).join('\n');
}
}
Phase 4: Cross-Task Knowledge Transfer
Problem: Tasks are isolated. Knowledge learned in Task A doesn't help Task B even if they're similar.
Solution: Build a knowledge graph connecting tasks, decisions, and outcomes.
// New: agent-knowledge-graph.service.ts
interface KnowledgeNode {
id: string;
type: 'task' | 'decision' | 'pattern' | 'file' | 'concept';
data: any;
}
interface KnowledgeEdge {
from: string;
to: string;
type: 'contains' | 'led_to' | 'similar_to' | 'mentions' | 'depends_on';
weight: number;
}
class AgentKnowledgeGraphService {
/**
* Add a new task to the knowledge graph
*/
async addTask(task: AgentTask): Promise<void> {
// Create task node
await this.addNode({ id: task.id, type: 'task', data: task });
// Link to similar past tasks
const similarTasks = await this.findSimilarTasks(task);
for (const similar of similarTasks) {
await this.addEdge({
from: task.id,
to: similar.id,
type: 'similar_to',
weight: similar.similarity
});
}
// Extract and link concepts
const concepts = await this.extractConcepts(task.goal);
for (const concept of concepts) {
await this.addNode({ id: concept.id, type: 'concept', data: concept });
await this.addEdge({
from: task.id,
to: concept.id,
type: 'mentions',
weight: 1
});
}
}
/**
* Get knowledge relevant to a new task
* Traverses the graph to find related successful patterns
*/
async getRelevantKnowledge(
taskGoal: string,
taskType: AgentTaskType
): Promise<RelevantKnowledge> {
// Find similar tasks
const similarTasks = await this.findSimilarTasks({ goal: taskGoal, type: taskType });
// Get their successful decisions
const successfulDecisions: AgentDecision[] = [];
for (const task of similarTasks) {
const decisions = await this.getDecisionsForTask(task.id);
successfulDecisions.push(...decisions.filter(d => d.outcome?.wasCorrect));
}
// Get learned patterns from those decisions
const patterns = await this.patternService.getPatternsFromDecisions(successfulDecisions);
// Get relevant files from similar tasks
const relevantFiles = await this.getCommonFilesFromTasks(similarTasks);
return {
similarTasks: similarTasks.slice(0, 3),
learnedPatterns: patterns.slice(0, 5),
suggestedFiles: relevantFiles.slice(0, 10),
successfulApproaches: this.summarizeApproaches(successfulDecisions)
};
}
/**
* When a task completes, propagate learnings
*/
async propagateLearnings(taskId: string, feedback: LearningFeedback): Promise<void> {
if (feedback.qualityRating >= 4) {
// Find similar tasks that might benefit
const task = await this.taskService.getTask(taskId);
const similarTasks = await this.findSimilarTasks(task);
for (const similar of similarTasks) {
// Add "led_to_success" edge
await this.addEdge({
from: taskId,
to: similar.id,
type: 'led_to',
weight: feedback.qualityRating / 5
});
}
}
}
}
Phase 5: Smart Context Window Management
Problem: Even with compression, context windows fill up. We need smarter allocation.
Solution: Multi-tier context with dynamic prioritization.
// Enhanced: agent-context.service.ts
interface ContextTier {
name: string;
tokenBudget: number;
priority: 'critical' | 'high' | 'medium' | 'low';
compressionLevel: 'none' | 'light' | 'heavy' | 'summary-only';
}
class EnhancedAgentContextService {
private readonly tiers: ContextTier[] = [
{ name: 'current-step', tokenBudget: 4000, priority: 'critical', compressionLevel: 'none' },
{ name: 'recent-decisions', tokenBudget: 2000, priority: 'high', compressionLevel: 'light' },
{ name: 'learned-patterns', tokenBudget: 1500, priority: 'high', compressionLevel: 'light' },
{ name: 'similar-tasks', tokenBudget: 1500, priority: 'medium', compressionLevel: 'heavy' },
{ name: 'project-context', tokenBudget: 2000, priority: 'medium', compressionLevel: 'heavy' },
{ name: 'file-summaries', tokenBudget: 1500, priority: 'low', compressionLevel: 'summary-only' },
{ name: 'historical', tokenBudget: 500, priority: 'low', compressionLevel: 'summary-only' }
];
/**
* Build optimized context for a session
* Dynamically allocates tokens based on task needs
*/
async buildOptimizedContext(
taskId: string,
options: {
totalBudget?: number;
focusAreas?: string[];
excludePatterns?: boolean;
} = {}
): Promise<OptimizedContext> {
const totalBudget = options.totalBudget || 12000; // ~12K tokens default
const task = await this.taskService.getTask(taskId);
// Dynamically adjust tier budgets based on task complexity
const adjustedTiers = this.adjustTierBudgets(task, totalBudget);
const context: OptimizedContext = {
currentStep: await this.getCurrentStepContext(task, adjustedTiers[0]),
recentDecisions: await this.getRecentDecisionsContext(task, adjustedTiers[1]),
learnedPatterns: options.excludePatterns
? ''
: await this.getLearnedPatternsContext(task, adjustedTiers[2]),
similarTasks: await this.getSimilarTasksContext(task, adjustedTiers[3]),
projectContext: await this.getProjectContext(task, adjustedTiers[4]),
fileSummaries: await this.getFileSummariesContext(task, adjustedTiers[5]),
historical: await this.getHistoricalContext(task, adjustedTiers[6]),
metadata: {
totalTokens: 0, // Calculate after building
tierBreakdown: {},
retrievalSources: []
}
};
// Calculate actual token usage
context.metadata.totalTokens = this.calculateTotalTokens(context);
return context;
}
/**
* Progressive summarization for long-running tasks
* As context ages, compress it further
*/
async progressivelySummarize(taskId: string): Promise<void> {
const task = await this.taskService.getTask(taskId);
const sessions = task.sessions;
for (let i = 0; i < sessions.length; i++) {
const session = sessions[i];
const age = Date.now() - new Date(session.endedAt || session.startedAt).getTime();
const ageInDays = age / (1000 * 60 * 60 * 24);
if (ageInDays > 7 && !session.compressedSummary) {
// Sessions older than 7 days get heavily compressed
session.compressedSummary = await this.heavyCompress(session);
session.decisionsLog = session.decisionsLog.slice(-3); // Keep only last 3 decisions
} else if (ageInDays > 1 && session.decisionsLog.length > 10) {
// Sessions older than 1 day get lightly compressed
session.decisionsLog = await this.lightCompress(session.decisionsLog);
}
}
await task.save();
}
/**
* Use AI to heavily compress a session into key learnings
*/
private async heavyCompress(session: AgentSession): Promise<string> {
const prompt = `Compress this AI agent session into a brief summary of key learnings (max 200 words):
Agent Type: ${session.agentType}
Duration: ${session.metrics.durationMs}ms
Decisions Made: ${session.decisionsLog.length}
Steps Completed: ${session.metrics.stepsCompleted}
Key Decisions:
${session.decisionsLog.map(d => `- ${d.type}: ${d.question} → ${d.chosen}`).join('\n')}
Handoff Notes: ${session.handoffNotes}
Provide:
1. Main accomplishments (1-2 sentences)
2. Key decisions and why (2-3 bullets)
3. Learnings for future sessions (1-2 bullets)`;
return await this.aiService.generate(prompt);
}
}
Phase 6: Agent Specialization Memory
Problem: All agents share the same learning pool. A UI specialist should learn differently from an API specialist.
Solution: Per-agent-type memory with shared base knowledge.
// New: agent-specialization-memory.service.ts
interface AgentSpecializationMemory {
agentType: AgentType;
specialization?: AgentSpecialization;
// Agent-specific patterns
learnedPatterns: LearnedPattern[];
// Agent-specific calibration
confidenceCalibration: Map<DecisionType, number>;
// Top performing decisions for this agent type
topDecisions: AgentDecision[];
// Common mistakes to avoid
antiPatterns: AntiPattern[];
// Files this agent type commonly works with
commonFilePatterns: string[];
}
class AgentSpecializationMemoryService {
/**
* Get specialized context for a specific agent type
*/
async getSpecializedContext(
agentType: AgentType,
specialization?: AgentSpecialization
): Promise<SpecializedContext> {
const memory = await this.getMemory(agentType, specialization);
return {
relevantPatterns: memory.learnedPatterns.slice(0, 3),
calibratedConfidence: memory.confidenceCalibration,
fewShotExamples: this.formatFewShotExamples(memory.topDecisions),
thingsToAvoid: memory.antiPatterns.slice(0, 3),
suggestedFilePatterns: memory.commonFilePatterns
};
}
/**
* Update agent memory after session
*/
async updateFromSession(
session: AgentSession,
feedback?: LearningFeedback
): Promise<void> {
const memory = await this.getOrCreateMemory(session.agentType, session.specialization);
// Update confidence calibration based on outcomes
if (feedback) {
for (const decision of session.decisionsLog) {
const currentCalibration = memory.confidenceCalibration.get(decision.type) || 0;
const actualOutcome = feedback.qualityRating / 5;
const delta = decision.confidence - actualOutcome;
// Exponential moving average
const alpha = 0.1;
const newCalibration = currentCalibration * (1 - alpha) + delta * alpha;
memory.confidenceCalibration.set(decision.type, newCalibration);
}
}
// Add high-quality decisions to top decisions
if (feedback?.qualityRating >= 4) {
memory.topDecisions.push(...session.decisionsLog);
memory.topDecisions = memory.topDecisions
.sort((a, b) => (b.outcome?.qualityRating || 0) - (a.outcome?.qualityRating || 0))
.slice(0, 100); // Keep top 100
}
// Learn anti-patterns from failures
if (feedback?.qualityRating <= 2) {
const antiPattern = await this.extractAntiPattern(session);
if (antiPattern) {
memory.antiPatterns.push(antiPattern);
}
}
await this.saveMemory(memory);
}
/**
* Extract an anti-pattern from a failed session
*/
private async extractAntiPattern(session: AgentSession): Promise<AntiPattern | null> {
const prompt = `This AI agent session received a poor rating. Extract an anti-pattern to avoid:
Agent Type: ${session.agentType}
Handoff Notes: ${session.handoffNotes}
Decisions Made:
${session.decisionsLog.map(d => `
- ${d.type}: ${d.question}
Chose: ${d.chosen}
Reasoning: ${d.reasoning}
Confidence: ${d.confidence}
`).join('\n')}
If there's a clear mistake or anti-pattern, describe:
1. What went wrong
2. What to avoid in future
3. What to do instead
Return null if no clear anti-pattern.`;
const response = await this.aiService.generate(prompt);
return JSON.parse(response);
}
}
📊 Implementation Priority Matrix
| Phase | Impact | Effort | Dependencies | Priority |
|---|---|---|---|---|
| 1. Vector Memory & RAG | 🔥🔥🔥🔥🔥 | Medium | MongoDB Atlas Vector Search | P0 |
| 2. Outcome Correlation | 🔥🔥🔥🔥 | Low | Phase 1 | P0 |
| 3. Pattern Mining | 🔥🔥🔥🔥 | Medium | Phase 1, 2 | P1 |
| 4. Knowledge Graph | 🔥🔥🔥 | High | Phase 1 | P2 |
| 5. Smart Context | 🔥🔥🔥🔥 | Medium | None | P1 |
| 6. Agent Specialization | 🔥🔥🔥 | Medium | Phase 1, 2 | P2 |
🛠️ Technical Requirements
Infrastructure Needed
MongoDB Atlas Vector Search or Pinecone
- For storing and querying decision embeddings
- ~1536 dimensions for OpenAI embeddings
- Cosine similarity search
AI Embedding API
- OpenAI
text-embedding-3-small(cheap, fast) - Or Cohere
embed-english-v3.0(good for code)
- OpenAI
Background Job Processing
- For pattern mining (daily cron)
- For progressive summarization
- Bull queue or agenda
Extended MongoDB Schemas
agent_embeddingscollectionagent_patternscollectionagent_calibrationscollection
Estimated Costs
| Component | Monthly Cost |
|---|---|
| MongoDB Atlas (M10) | ~$57/mo |
| Vector Search (included in M10+) | $0 |
| OpenAI Embeddings (100K decisions) | ~$5/mo |
| AI for Pattern Mining | ~$10-20/mo |
| Total | ~$75-85/mo |
🎯 Success Metrics
After implementing these enhancements:
Decision Quality should improve 20-40%
- Track user ratings before/after
Confidence Calibration should reach ±10%
- Predicted confidence within 10% of actual outcome
Context Relevance should improve
- Measure by user "context was helpful" feedback
Cross-Task Learning should show
- Similar tasks complete faster
- Fewer repeated mistakes
Pattern Library should grow
- 50+ high-quality patterns within 3 months
- 80%+ success rate patterns prioritized
📁 New Files to Create
apis/backend-api/src/app/ai-agents/
├── services/
│ ├── agent-vector-memory.service.ts # Phase 1
│ ├── agent-outcome-correlation.service.ts # Phase 2
│ ├── agent-pattern-mining.service.ts # Phase 3
│ ├── agent-knowledge-graph.service.ts # Phase 4
│ └── agent-specialization-memory.service.ts # Phase 6
├── schemas/
│ ├── agent-embedding.schema.ts # Phase 1
│ ├── agent-pattern.schema.ts # Phase 3
│ └── agent-calibration.schema.ts # Phase 2
├── jobs/
│ ├── pattern-mining.job.ts # Phase 3
│ └── progressive-compression.job.ts # Phase 5
└── enhanced/
└── enhanced-context.service.ts # Phase 5
🚀 Quick Start: Phase 1 Implementation
To get started with the highest-impact improvement:
# 1. Enable MongoDB Atlas Vector Search on your cluster
# (Requires M10+ tier)
# 2. Create the vector search index
mongosh "mongodb+srv://your-cluster" --eval '
db.agent_embeddings.createSearchIndex({
"name": "decision_vector_index",
"type": "vectorSearch",
"definition": {
"fields": [{
"type": "vector",
"numDimensions": 1536,
"path": "embedding",
"similarity": "cosine"
}]
}
})
'
# 3. Add OpenAI embedding to backend .env
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
# 4. Implement AgentVectorMemoryService
# (See code above)
Last Updated: December 2025 Status: Enhancement Proposal Ready for Implementation