Decision Tree Logic Phase 3.3 of the Gmail Memory-as-a-Tool system.
Overview The Decision Tree is the core logic that determines what to do with a new memory extracted from an email:
Compare the new memory against existing memories using similarity search
Decide whether to CREATE, UPDATE, SKIP, or DELETE
Execute the decision and log it for audit
Decision Types Decision
When
Action
CREATE
No similar memory (score < 0.50) or related (0.50-0.80)
Create new MemoryNode
UPDATE
Similar memory exists (score 0.80-0.95)
Update existing MemoryNode
SKIP
Duplicate detected (score >= 0.95)
Do nothing, log only
DELETE
User/source deletion request
Soft delete MemoryNode
Decision Flow New Memory ( from extraction)
│
▼
┌───────────────────┐
│ Similarity Search │ → Compare against existing memories
└───────────────────┘
│
▼
┌───────────────────┐
│ Get Best Match │ → Find highest scoring match
└───────────────────┘
│
▼
┌───────────────────────────────────────────────────┐
│ Score Evaluation │
├───────────────────────────────────────────────────┤
│ >= 0.95 ( DUPLICATE ) → SKIP │
│ 0.80 - 0.95 ( UPDATE ) → UPDATE existing memory │
│ 0.50 - 0.80 ( RELATED ) → CREATE + link to related │
│ < 0.50 ( UNRELATED ) → CREATE new memory │
└───────────────────────────────────────────────────┘
│
▼
┌───────────────────┐
│ Execute Decision │ → Write to graph DB
└───────────────────┘
│
▼
┌───────────────────┐
│ Log Decision │ → Audit trail
└───────────────────┘
Example Scenarios Scenario 1: CREATE (New Information) Email:
Subject: Q1 마케팅 캠페인 킥오프
Content: Q1 마케팅 캠페인을 1 월 15 일에 시작합니다 . 예산은 5000 만원입니다
Extracted Memory:
{
"tempId" : "temp_001" ,
"content" : "Q1 마케팅 캠페인: 시작일 1월 15일, 예산 5000만원" ,
"category" : "project" ,
"importance" : 0.8
}
Similarity Search Result:
Best match: None ( no similar memories)
Score: N /A
Decision:
{
"decision" : "CREATE" ,
"reason" : "No similar memories found. Creating new memory." ,
"action" : {
"type" : "create" ,
"memoryData" : { ... }
}
}
Scenario 2: UPDATE (Information Changed) New Email (follow-up):
Subject: Re: Q1 마케팅 캠페인 킥오프
Content: 예산이 6000 만원으로 증액되었습니다
Similarity Search Result:
Best match: mem_001 ( Q1 마케팅 캠페인)
Score: 0.87
Category: UPDATE
Factors:
- content : 0.82 ( semantically similar)
- threadId : 1.0 ( same thread)
- people : 1.0 ( same participants)
Decision:
{
"decision" : "UPDATE" ,
"targetMemoryId" : "mem_001" ,
"reason" : "High similarity (0.87) with existing memory. Updating with new info." ,
"action" : {
"type" : "update" ,
"targetId" : "mem_001" ,
"updates" : {
"content" : "Q1 마케팅 캠페인: 시작일 1월 15일, 예산 6000만원 (증액)"
} ,
"createVersion" : true
}
}
Scenario 3: SKIP (Duplicate) New Email (forwarded):
Subject: Fwd: Q1 마케팅 캠페인 킥오프
Content: ( 동일한 내용 포워드)
Similarity Search Result:
Best match: mem_001
Score: 0.97
Category: DUPLICATE
Decision:
{
"decision" : "SKIP" ,
"targetMemoryId" : "mem_001" ,
"reason" : "Duplicate detected (score: 0.97). Memory already exists." ,
"action" : {
"type" : "skip" ,
"duplicateOfId" : "mem_001" ,
"duplicateScore" : 0.97
}
}
Scenario 4: CREATE + LINK (Related but Different) New Email (different topic, same project):
Subject: Q2 마케팅 예산 논의
Content: Q2 마케팅 예산으로 8000 만원을 요청드립니다
Similarity Search Result:
Best match: mem_001 ( Q1 마케팅 캠페인)
Score: 0.65
Category: RELATED
Decision:
{
"decision" : "CREATE" ,
"reason" : "Related content (0.65) but distinct topic. Creating new memory and linking." ,
"action" : {
"type" : "create" ,
"memoryData" : { ... } ,
"relatedMemoryIds" : [ "mem_001" ] ,
"relationshipType" : "related_to"
}
}
Scenario 5: DELETE (User Request) User Input:
Decision:
{
"decision" : "DELETE" ,
"targetMemoryId" : "mem_001" ,
"reason" : "User requested deletion" ,
"action" : {
"type" : "delete" ,
"targetId" : "mem_001" ,
"trigger" : "user_request" ,
"softDelete" : true ,
"cascadeMode" : "preserve_edges"
}
}
Conflict Resolution When updating a memory, conflicts may arise if the new data has a lower priority source than the existing data.
Source Priority Order Priority
Source Type
Example
1 (Highest)
USER_INPUT
User manually entered
2
BOOTSTRAPPED
Initial data import
3
TOOL_OUTPUT
MCP tool result
4 (Lowest)
REALTIME
Live email extraction
Resolution Rules Higher priority wins : If new data has lower priority, keep existing data
Same priority : Use newer timestamp
Override option : respectSourcePriority: false ignores priority
Example:
{ content: "예산 5000만원" , sourceType : "user_input" }
{ content: "예산 6000만원" , sourceType : "realtime" }
Merge Strategies When updating, different fields can be merged differently:
Field
Strategy Options
Default
content
replace, append, keep_existing
replace
keywords
replace, merge, keep_existing
merge
importance
replace, max, keep_existing
max
Type Definitions See: lib/types/consolidation.ts
Key Types
enum DecisionType {
CREATE = 'create' ,
UPDATE = 'update' ,
SKIP = 'skip' ,
DELETE = 'delete' ,
}
interface DecisionContext {
newMemory: NewMemoryInput ;
similarityResults: SimilarityResult [ ] ;
bestMatch ?: MemoryComparisonResult ;
trigger: ConsolidationTrigger ;
userId: string ;
}
interface DecisionResult {
decision: DecisionType ;
targetMemoryId ?: string ;
reason: string ;
action: DecisionAction ;
}
Decision Logging Every decision is logged for audit and debugging. See: lib/types/decision-log.ts
Log Entry Structure interface DecisionLogEntry {
id: string ;
timestamp: Date ;
userId: string ;
decision: DecisionType ;
inputMemoryId: string ;
targetMemoryId ?: string ;
similarityScore ?: number ;
reason: string ;
action: DecisionAction ;
status: 'success' | 'error' | 'skipped' | 'dry_run' ;
processingTimeMs: number ;
}
Querying Logs
const skippedLogs = await logStorage .query ( {
userId : 'user_123' ,
decision : DecisionType .SKIP ,
dateRange : { from : lastWeek , to : now } ,
} ) ;
const analytics = await logStorage .getAnalytics ( {
userId : 'user_123' ,
} ) ;
Related Documentation Similarity Types - Similarity scoring system
Conflict Resolution - Priority rules
Importance Scoring - How importance is calculated