Session 75.15 Implementation Summary
Documentation for Sessions
Session 75.15: Two-Layer Agent Intelligence Implementation Summary
Date: 2026-01-31 Branch: editor2-session-75.5 Status: Core Implementation Complete
What Was Built
1. Cross-Space User Agent Memories
Location: gograb-api.user_agent_memories
A system that lets AI agents truly KNOW users across all their Spaces:
// Schema: libs/libs-api/backend-core/src/lib/schemas/user-agent-memory.schema.ts
interface UserAgentMemory {
userId: ObjectId;
agentId: string; // 'vitto', 'claude-code', etc.
memoryType: 'preference' | 'fact' | 'skill' | 'personality' | 'interaction';
key: string; // 'response_style', 'coding_language', etc.
value: Record<string, any>;
confidence: number; // 0-1, grows with reinforcement
source: 'observed' | 'stated' | 'inferred';
learnedFromSpaces: string[]; // Audit trail
}
Key Features:
- Upsert on
userId + agentId + key(no duplicates) - Confidence reinforcement/weakening with atomic MongoDB operations
- Privacy checks before saving (respects
crossSpaceLearning: false) - TTL support for temporary memories
- GDPR-compliant forget operations
2. Global User Preferences
Location: gograb-api.user_preferences
User's default preferences that apply across all Spaces:
// Schema: libs/libs-api/backend-core/src/lib/schemas/user-preferences.schema.ts
interface UserPreferences {
userId: ObjectId;
theme: 'light' | 'dark' | 'auto';
language: string;
timezone: string;
agentPrivacy: {
crossSpaceLearning: boolean;
memoryRetention: '30d' | '90d' | '1y' | 'forever';
blockedAgents: string[];
};
notifications: NotificationPreferences;
interface: InterfacePreferences;
aiAssistant: AIAssistantPreferences;
}
3. VITTO Memory Integration
Location: apis/backend-ai-api/src/app/vitto/vitto-orchestrator.service.ts
VITTO now:
- Loads user memories before AI execution
- Includes memories in system prompt for personalization
- Saves interaction learnings after task completion
// Memory loading for AI context
const userContext = await this.loadUserContext(userId);
// Returns formatted context like:
// ## What I know about this user:
// **Preferences:**
// - response_style: {"style": "concise"} (confidence: 0.80)
// **Skills/Expertise:**
// - coding_language: {"primary": "TypeScript"}
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ User Request │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ backend-ai-api (VITTO) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ VittoOrchestratorService │ │
│ │ └─ loadUserContext(userId) ─────┐ │ │
│ │ └─ saveUserLearning(...) │ │ │
│ │ └─ reinforceUserMemory(...) │ │ │
│ └──────────────────────────────────│────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ UserAgentMemoryModule │ │
│ │ └─ UserAgentService (from @libs-api/backend-core) │ │
│ │ └─ UserPreferencesService │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
AI_CONNECTION_NAMES.PLATFORM
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ gograb-api (MongoDB) │
│ ├── user_agent_memories (WHO the user is) │
│ └── user_preferences (Global defaults + privacy) │
└─────────────────────────────────────────────────────────────────────┘
Files Changed/Created
New Files
| File | Purpose |
|---|---|
libs/libs-api/backend-core/src/lib/schemas/user-agent-memory.schema.ts |
Memory schema |
libs/libs-api/backend-core/src/lib/schemas/user-preferences.schema.ts |
Preferences schema |
libs/libs-api/backend-core/src/lib/services/user-agent.service.ts |
Memory CRUD |
libs/libs-api/backend-core/src/lib/services/user-preferences.service.ts |
Preferences CRUD |
apis/backend-ai-api/src/app/shared/user-agent-memory.module.ts |
Schema registration for AI API |
libs/libs-api/README.md |
Comprehensive library documentation |
Modified Files
| File | Change |
|---|---|
libs/libs-api/backend-core/src/index.ts |
Export new schemas/services |
libs/libs-api/backend-core/src/lib/config/database-names.config.ts |
Added AI_CONNECTION_NAMES.PLATFORM |
libs/libs-api/backend-core/src/lib/config/mongodb.factory.ts |
Added AI_MONGODB_OPTIONS.platform |
apis/backend-api/src/app/users/users.module.ts |
Import shared schemas/services |
apis/backend-api/src/app/users/users.controller.ts |
Added preferences/memory endpoints |
apis/backend-ai-api/src/app/app.module.ts |
Added PLATFORM connection |
apis/backend-ai-api/src/app/vitto/vitto.module.ts |
Import UserAgentMemoryModule |
apis/backend-ai-api/src/app/vitto/vitto-orchestrator.service.ts |
Added memory integration |
API Endpoints
User Preferences (backend-api)
GET /api/users/me/preferences # Get global preferences
PUT /api/users/me/preferences # Update preferences
GET /api/users/me/privacy-settings # Get privacy controls
PUT /api/users/me/privacy-settings # Update privacy
PUT /api/users/me/privacy-settings/block/:agentId # Block agent
DELETE /api/users/me/privacy-settings/block/:agentId # Unblock agent
Agent Memories (backend-api)
GET /api/users/me/agent-memories # List all memories
GET /api/users/me/agent-memories/:agentId # Memories from agent
GET /api/users/me/agent-memories-stats # Memory statistics
DELETE /api/users/me/agent-memories/:memoryId # Forget specific
DELETE /api/users/me/agent-memories/agent/:agentId # Forget all from agent
DELETE /api/users/me/agent-memories # Forget ALL (GDPR)
Bug Fixes Applied
- ObjectId Validation - All forget methods now validate IDs before creating ObjectId
- Confidence Race Condition - Uses atomic MongoDB aggregation pipeline with
$min/$max - Preference Overrides Fallback - SpaceDatabaseService creates defaults if missing
Usage Example
Saving a Memory (from VITTO or any agent)
await userAgentService.saveMemory({
userId: 'user-123',
agentId: 'vitto',
memoryType: 'preference',
key: 'response_style',
value: { style: 'concise', reason: 'User requested shorter answers' },
confidence: 0.8,
source: 'stated',
spaceId: 'space-abc',
});
Querying Memories
const memories = await userAgentService.getMemories({
userId: 'user-123',
agentId: 'vitto',
memoryType: 'preference',
minConfidence: 0.5,
limit: 20,
});
Reinforcing (user confirmed assumption)
await userAgentService.reinforceMemory('user-123', 'vitto', 'response_style', 0.1);
// Confidence increases by 0.1, capped at 1.0
Privacy Check
const canLearn = await userAgentService.canLearnFromUser('user-123', 'vitto');
// Returns false if user has blocked agent or disabled crossSpaceLearning
What's Still Outstanding
| Priority | Item | Notes |
|---|---|---|
| P2 | Rate limiting on memory saves | Prevent agent loops from flooding DB |
| P3 | Unit tests for PreferenceResolver | Complex branching logic needs coverage |
| P3 | Audit logging for admin actions | Accountability for preference config changes |
Key Design Decisions
- Direct MongoDB over HTTP - VITTO needs sub-10ms memory access during conversation
- @Optional() injection - VITTO works even if memory service unavailable
- Memories by agentId - Each agent maintains its own knowledge about users
- Confidence-based learning - Low initial confidence grows with reinforcement
- Privacy-first - All saves check user's privacy settings first