@zooique/memora 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/agent/agent.d.ts +343 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +893 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/assembler.d.ts +77 -0
- package/dist/agent/assembler.d.ts.map +1 -0
- package/dist/agent/assembler.js +115 -0
- package/dist/agent/assembler.js.map +1 -0
- package/dist/agent/builtinToolHandlers.d.ts +96 -0
- package/dist/agent/builtinToolHandlers.d.ts.map +1 -0
- package/dist/agent/builtinToolHandlers.js +388 -0
- package/dist/agent/builtinToolHandlers.js.map +1 -0
- package/dist/agent/builtinTools.d.ts +35 -0
- package/dist/agent/builtinTools.d.ts.map +1 -0
- package/dist/agent/builtinTools.js +75 -0
- package/dist/agent/builtinTools.js.map +1 -0
- package/dist/agent/constants.d.ts +67 -0
- package/dist/agent/constants.d.ts.map +1 -0
- package/dist/agent/constants.js +67 -0
- package/dist/agent/constants.js.map +1 -0
- package/dist/agent/contextManager.d.ts +130 -0
- package/dist/agent/contextManager.d.ts.map +1 -0
- package/dist/agent/contextManager.js +287 -0
- package/dist/agent/contextManager.js.map +1 -0
- package/dist/agent/loop.d.ts +288 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +756 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/managers/autoConfigRefiner.d.ts +39 -0
- package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -0
- package/dist/agent/managers/autoConfigRefiner.js +150 -0
- package/dist/agent/managers/autoConfigRefiner.js.map +1 -0
- package/dist/agent/managers/configManager.d.ts +114 -0
- package/dist/agent/managers/configManager.d.ts.map +1 -0
- package/dist/agent/managers/configManager.js +186 -0
- package/dist/agent/managers/configManager.js.map +1 -0
- package/dist/agent/managers/insightExtractor.d.ts +141 -0
- package/dist/agent/managers/insightExtractor.d.ts.map +1 -0
- package/dist/agent/managers/insightExtractor.js +420 -0
- package/dist/agent/managers/insightExtractor.js.map +1 -0
- package/dist/agent/managers/memoryAdvisor.d.ts +96 -0
- package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -0
- package/dist/agent/managers/memoryAdvisor.js +198 -0
- package/dist/agent/managers/memoryAdvisor.js.map +1 -0
- package/dist/agent/managers/memoryInspector.d.ts +231 -0
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -0
- package/dist/agent/managers/memoryInspector.js +327 -0
- package/dist/agent/managers/memoryInspector.js.map +1 -0
- package/dist/agent/managers/sessionManager.d.ts +89 -0
- package/dist/agent/managers/sessionManager.d.ts.map +1 -0
- package/dist/agent/managers/sessionManager.js +178 -0
- package/dist/agent/managers/sessionManager.js.map +1 -0
- package/dist/agent/managers/userFactExtractor.d.ts +25 -0
- package/dist/agent/managers/userFactExtractor.d.ts.map +1 -0
- package/dist/agent/managers/userFactExtractor.js +81 -0
- package/dist/agent/managers/userFactExtractor.js.map +1 -0
- package/dist/agent/managers/workProjection.d.ts +117 -0
- package/dist/agent/managers/workProjection.d.ts.map +1 -0
- package/dist/agent/managers/workProjection.js +290 -0
- package/dist/agent/managers/workProjection.js.map +1 -0
- package/dist/agent/messageHistory.d.ts +157 -0
- package/dist/agent/messageHistory.d.ts.map +1 -0
- package/dist/agent/messageHistory.js +288 -0
- package/dist/agent/messageHistory.js.map +1 -0
- package/dist/agent/toolExecutor.d.ts +137 -0
- package/dist/agent/toolExecutor.d.ts.map +1 -0
- package/dist/agent/toolExecutor.js +209 -0
- package/dist/agent/toolExecutor.js.map +1 -0
- package/dist/agent/tracer.d.ts +122 -0
- package/dist/agent/tracer.d.ts.map +1 -0
- package/dist/agent/tracer.js +64 -0
- package/dist/agent/tracer.js.map +1 -0
- package/dist/agent/types.d.ts +98 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +19 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/config/loader.d.ts +229 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +194 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/eval/evalTypes.d.ts +118 -0
- package/dist/eval/evalTypes.d.ts.map +1 -0
- package/dist/eval/evalTypes.js +102 -0
- package/dist/eval/evalTypes.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/embedding.d.ts +62 -0
- package/dist/llm/embedding.d.ts.map +1 -0
- package/dist/llm/embedding.js +162 -0
- package/dist/llm/embedding.js.map +1 -0
- package/dist/llm/factory.d.ts +39 -0
- package/dist/llm/factory.d.ts.map +1 -0
- package/dist/llm/factory.js +108 -0
- package/dist/llm/factory.js.map +1 -0
- package/dist/llm/openaiCompatible.d.ts +63 -0
- package/dist/llm/openaiCompatible.d.ts.map +1 -0
- package/dist/llm/openaiCompatible.js +340 -0
- package/dist/llm/openaiCompatible.js.map +1 -0
- package/dist/llm/provider.d.ts +91 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +14 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/types.d.ts +25 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +7 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/logging/logger.d.ts +39 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +279 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/loggerInterface.d.ts +33 -0
- package/dist/logging/loggerInterface.d.ts.map +1 -0
- package/dist/logging/loggerInterface.js +2 -0
- package/dist/logging/loggerInterface.js.map +1 -0
- package/dist/memory/inMemoryRelationStore.d.ts +51 -0
- package/dist/memory/inMemoryRelationStore.d.ts.map +1 -0
- package/dist/memory/inMemoryRelationStore.js +65 -0
- package/dist/memory/inMemoryRelationStore.js.map +1 -0
- package/dist/memory/inMemoryStorage.d.ts +97 -0
- package/dist/memory/inMemoryStorage.d.ts.map +1 -0
- package/dist/memory/inMemoryStorage.js +177 -0
- package/dist/memory/inMemoryStorage.js.map +1 -0
- package/dist/memory/loader.d.ts +49 -0
- package/dist/memory/loader.d.ts.map +1 -0
- package/dist/memory/loader.js +93 -0
- package/dist/memory/loader.js.map +1 -0
- package/dist/memory/projectManager.d.ts +182 -0
- package/dist/memory/projectManager.d.ts.map +1 -0
- package/dist/memory/projectManager.js +441 -0
- package/dist/memory/projectManager.js.map +1 -0
- package/dist/memory/recall.d.ts +77 -0
- package/dist/memory/recall.d.ts.map +1 -0
- package/dist/memory/recall.js +147 -0
- package/dist/memory/recall.js.map +1 -0
- package/dist/memory/relationStore.d.ts +78 -0
- package/dist/memory/relationStore.d.ts.map +1 -0
- package/dist/memory/relationStore.js +2 -0
- package/dist/memory/relationStore.js.map +1 -0
- package/dist/memory/sessionStore.d.ts +84 -0
- package/dist/memory/sessionStore.d.ts.map +1 -0
- package/dist/memory/sessionStore.js +2 -0
- package/dist/memory/sessionStore.js.map +1 -0
- package/dist/memory/storageInterface.d.ts +107 -0
- package/dist/memory/storageInterface.d.ts.map +1 -0
- package/dist/memory/storageInterface.js +2 -0
- package/dist/memory/storageInterface.js.map +1 -0
- package/dist/memory/store.d.ts +50 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +160 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.d.ts +189 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +230 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/memory/userProfile.d.ts +156 -0
- package/dist/memory/userProfile.d.ts.map +1 -0
- package/dist/memory/userProfile.js +315 -0
- package/dist/memory/userProfile.js.map +1 -0
- package/dist/memory/vectorStore.d.ts +75 -0
- package/dist/memory/vectorStore.d.ts.map +1 -0
- package/dist/memory/vectorStore.js +144 -0
- package/dist/memory/vectorStore.js.map +1 -0
- package/dist/persona/personaManager.d.ts +121 -0
- package/dist/persona/personaManager.d.ts.map +1 -0
- package/dist/persona/personaManager.js +349 -0
- package/dist/persona/personaManager.js.map +1 -0
- package/dist/persona/types.d.ts +32 -0
- package/dist/persona/types.d.ts.map +1 -0
- package/dist/persona/types.js +5 -0
- package/dist/persona/types.js.map +1 -0
- package/dist/security/pathGuard.d.ts +121 -0
- package/dist/security/pathGuard.d.ts.map +1 -0
- package/dist/security/pathGuard.js +276 -0
- package/dist/security/pathGuard.js.map +1 -0
- package/dist/skill/skillManager.d.ts +82 -0
- package/dist/skill/skillManager.d.ts.map +1 -0
- package/dist/skill/skillManager.js +198 -0
- package/dist/skill/skillManager.js.map +1 -0
- package/dist/skill/types.d.ts +28 -0
- package/dist/skill/types.d.ts.map +1 -0
- package/dist/skill/types.js +5 -0
- package/dist/skill/types.js.map +1 -0
- package/dist/utils/errors.d.ts +86 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +143 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/eventEmitter.d.ts +87 -0
- package/dist/utils/eventEmitter.d.ts.map +1 -0
- package/dist/utils/eventEmitter.js +79 -0
- package/dist/utils/eventEmitter.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +24 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +44 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/json.d.ts +20 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +65 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/loggerHolder.d.ts +37 -0
- package/dist/utils/loggerHolder.d.ts.map +1 -0
- package/dist/utils/loggerHolder.js +49 -0
- package/dist/utils/loggerHolder.js.map +1 -0
- package/dist/utils/math.d.ts +5 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +19 -0
- package/dist/utils/math.js.map +1 -0
- package/dist/utils/path.d.ts +28 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +33 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/safeTimer.d.ts +26 -0
- package/dist/utils/safeTimer.d.ts.map +1 -0
- package/dist/utils/safeTimer.js +49 -0
- package/dist/utils/safeTimer.js.map +1 -0
- package/dist/utils/scanner.d.ts +54 -0
- package/dist/utils/scanner.d.ts.map +1 -0
- package/dist/utils/scanner.js +115 -0
- package/dist/utils/scanner.js.map +1 -0
- package/dist/utils/segmenter.d.ts +30 -0
- package/dist/utils/segmenter.d.ts.map +1 -0
- package/dist/utils/segmenter.js +80 -0
- package/dist/utils/segmenter.js.map +1 -0
- package/dist/utils/strings.d.ts +18 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +25 -0
- package/dist/utils/strings.js.map +1 -0
- package/dist/utils/time.d.ts +23 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +31 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/toError.d.ts +13 -0
- package/dist/utils/toError.d.ts.map +1 -0
- package/dist/utils/toError.js +22 -0
- package/dist/utils/toError.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户画像管理 — 实时归档 + SQLite 持久化
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* - 每轮对话结束后扫描是否产生新画像条目
|
|
6
|
+
* - 5 个子分类:identity / preference / expertise / habit / history
|
|
7
|
+
* - 实时归档(用户前脚说"我叫张三"→ 后脚就写入 SQLite)
|
|
8
|
+
* - 启动时从 SQLite 全量加载(source = 'profile')
|
|
9
|
+
* - confidence 机制:高置信度(≥0.8)直接归档,低置信度首次召回时确认
|
|
10
|
+
*
|
|
11
|
+
* 设计原则(architecture_philosophy_rules.md §2 永久性分级):
|
|
12
|
+
* - 用户画像属于助手记忆,source = 'profile',每轮必召回
|
|
13
|
+
* - 实时归档解决"重启进程短期身份丢失"的核心 bug
|
|
14
|
+
* - 确认机制防止正则误归档污染画像
|
|
15
|
+
* - identity / preference / expertise 实时归档,habit / history 每天归档时提炼
|
|
16
|
+
*/
|
|
17
|
+
import type { IMemoryStorage } from '../memory/storageInterface.js';
|
|
18
|
+
/** 用户画像子分类 */
|
|
19
|
+
export type ProfileCategory = 'identity' | 'preference' | 'expertise' | 'habit' | 'history';
|
|
20
|
+
/** 用户画像条目 */
|
|
21
|
+
export interface UserProfileEntry {
|
|
22
|
+
/** 画像唯一 ID(格式:profile:user-profile-{category}-{slug}) */
|
|
23
|
+
id: string;
|
|
24
|
+
/** 子分类 */
|
|
25
|
+
category: ProfileCategory;
|
|
26
|
+
/** 事实值(如 "姓名: 张三") */
|
|
27
|
+
value: string;
|
|
28
|
+
/** 来源(哪一轮对话提到) */
|
|
29
|
+
source: string;
|
|
30
|
+
/** 权重(0-1) */
|
|
31
|
+
weight: number;
|
|
32
|
+
/** 是否已确认(false 表示首次召回时需用户确认) */
|
|
33
|
+
confirmed: boolean;
|
|
34
|
+
/** 最后更新时间(ISO 8601) */
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
}
|
|
37
|
+
/** extractUserFacts 的原始提取结果 */
|
|
38
|
+
export interface ExtractedFact {
|
|
39
|
+
category: ProfileCategory;
|
|
40
|
+
value: string;
|
|
41
|
+
sourceTurn: string;
|
|
42
|
+
/** 置信度 0-1(≥0.8 直接归档,否则标记待确认) */
|
|
43
|
+
confidence: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 用户画像管理器
|
|
47
|
+
*/
|
|
48
|
+
export declare class UserProfile {
|
|
49
|
+
private readonly index;
|
|
50
|
+
/** 内存缓存:启动时从 SQLite 全量加载 */
|
|
51
|
+
private cache;
|
|
52
|
+
constructor(index: IMemoryStorage);
|
|
53
|
+
/**
|
|
54
|
+
* 启动时从 SQLite 加载所有已确认的画像条目
|
|
55
|
+
*
|
|
56
|
+
* 存储中只保存已确认的条目(confirmed = true),
|
|
57
|
+
* 待确认条目仅存内存缓存,不写入存储。
|
|
58
|
+
*
|
|
59
|
+
* P2-5 content 字段使用 JSON 编码存储 category + value 元数据,
|
|
60
|
+
* 兼容旧格式(name 字段 "${category}: ${value}")作为降级路径。
|
|
61
|
+
*/
|
|
62
|
+
load(): Promise<UserProfileEntry[]>;
|
|
63
|
+
/**
|
|
64
|
+
* 实时归档:将提取的用户事实写入存储
|
|
65
|
+
*
|
|
66
|
+
* 每轮 chat() 结束后,由 Agent 调用 extractUserFacts() 提取事实后传入。
|
|
67
|
+
* 高置信度(≥0.8)→ 直接归档为 confirmed
|
|
68
|
+
* 低置信度 → 标记 confirmed = false,首次召回时 Agent 向用户确认
|
|
69
|
+
*
|
|
70
|
+
* @param facts 由 extractUserFacts() 提取的事实列表
|
|
71
|
+
*/
|
|
72
|
+
archiveFacts(facts: ExtractedFact[]): Promise<number>;
|
|
73
|
+
/**
|
|
74
|
+
* 获取所有已确认的画像条目(system prompt 注入用)
|
|
75
|
+
*/
|
|
76
|
+
getConfirmed(): UserProfileEntry[];
|
|
77
|
+
/**
|
|
78
|
+
* 获取所有待确认的画像条目(供宿主 UI 展示确认/拒绝操作)
|
|
79
|
+
*
|
|
80
|
+
* 待确认条目仅存内存缓存(未写入存储),进程重启后丢失。
|
|
81
|
+
* 宿主应定期或在新对话后查询此方法,展示给用户确认。
|
|
82
|
+
*/
|
|
83
|
+
getPending(): UserProfileEntry[];
|
|
84
|
+
/**
|
|
85
|
+
* 构建 system prompt 中的用户画像段
|
|
86
|
+
*
|
|
87
|
+
* 格式:
|
|
88
|
+
* 【用户画像】
|
|
89
|
+
* - 身份:张三,男,25岁,住北京
|
|
90
|
+
* - 偏好:TypeScript, Python, VS Code
|
|
91
|
+
* - 专长:后端开发,系统架构
|
|
92
|
+
* - 习惯:上午工作,下午思考
|
|
93
|
+
*/
|
|
94
|
+
buildSystemPrompt(): string;
|
|
95
|
+
/**
|
|
96
|
+
* 确认待确认条目(用户在对话中确认了)
|
|
97
|
+
*
|
|
98
|
+
* 确认后写入存储(此前仅存内存缓存)
|
|
99
|
+
*
|
|
100
|
+
* @param id 条目 ID
|
|
101
|
+
*/
|
|
102
|
+
confirm(id: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* 拒绝待确认条目(用户在对话中否认了)
|
|
105
|
+
*
|
|
106
|
+
* @param id 条目 ID
|
|
107
|
+
*/
|
|
108
|
+
reject(id: string): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* 写入单条事实到 SQLite
|
|
111
|
+
*
|
|
112
|
+
* 冲突解决策略:
|
|
113
|
+
* 同分类(identity/preference/expertise/habit/history)的新事实
|
|
114
|
+
* 会替换旧事实。因为用户画像是"当前状态"而非"历史记录"。
|
|
115
|
+
* 例:"我叫张三" → 后续说"我叫李四" → 只保留"李四",张三被移除。
|
|
116
|
+
*
|
|
117
|
+
* @returns 成功写入的条目,或 null(写入失败)
|
|
118
|
+
*/
|
|
119
|
+
private upsertFact;
|
|
120
|
+
/**
|
|
121
|
+
* 删除同分类的旧条目(用户更新了信息)
|
|
122
|
+
*
|
|
123
|
+
* 当用户说"我叫李四"替换之前的"我叫张三"时,移除旧的 identity 条目。
|
|
124
|
+
* 策略:同分类(category)下,新值替换旧值。判断标准是旧条目的 value 前缀。
|
|
125
|
+
*
|
|
126
|
+
* P2-5 从 content JSON 解码 category,替代 name 字段隐式解析。
|
|
127
|
+
* P2-3 构建 contentPrefix → entry 的 Map 索引,冲突检测从 O(n*m) 降为 O(m)。
|
|
128
|
+
*
|
|
129
|
+
* @param fact 当前提取到的新事实
|
|
130
|
+
*/
|
|
131
|
+
private removeConflictingEntries;
|
|
132
|
+
/**
|
|
133
|
+
* 将 UserProfileEntry 转为 Memory(用于写入 SQLite)
|
|
134
|
+
*
|
|
135
|
+
* P2-5 content 字段使用 JSON 编码存储 category + value 元数据,
|
|
136
|
+
* name 字段为固定可读标签,category 通过 content 的 JSON 元数据显式编码。
|
|
137
|
+
* 确认状态:仅已确认条目调用此方法(待确认条目不写入存储)
|
|
138
|
+
*/
|
|
139
|
+
private toMemory;
|
|
140
|
+
/**
|
|
141
|
+
* 从 content 字段解析 category 和 value
|
|
142
|
+
*
|
|
143
|
+
* P2-5 优先从 content JSON 解码元数据,降级到旧格式 name 字段解析,
|
|
144
|
+
* 确保已有 SQLite 数据(旧格式 name="${category}: ${value}")兼容加载。
|
|
145
|
+
*
|
|
146
|
+
* @param content Memory 的 content 字段(新格式为 JSON,旧格式为纯 value)
|
|
147
|
+
* @param name Memory 的 name 字段(旧格式为 "${category}: ${value}")
|
|
148
|
+
* @returns 解析出的 category 和 value
|
|
149
|
+
*/
|
|
150
|
+
private parseContentField;
|
|
151
|
+
/**
|
|
152
|
+
* 分类标签
|
|
153
|
+
*/
|
|
154
|
+
private categoryLabel;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=userProfile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userProfile.d.ts","sourceRoot":"","sources":["../../src/memory/userProfile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnE,cAAc;AACd,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;AAE5F,aAAa;AACb,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,UAAU;IACV,QAAQ,EAAE,eAAe,CAAC;IAC1B,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHlC,4BAA4B;IAC5B,OAAO,CAAC,KAAK,CAA4C;gBAE5B,KAAK,EAAE,cAAc;IAElD;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAgCzC;;;;;;;;OAQG;IACG,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAW3D;;OAEG;IACH,YAAY,IAAI,gBAAgB,EAAE;IAIlC;;;;;OAKG;IACH,UAAU,IAAI,gBAAgB,EAAE;IAIhC;;;;;;;;;OASG;IACH,iBAAiB,IAAI,MAAM;IA0B3B;;;;;;OAMG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAavC;;;;;;;;;OASG;YACW,UAAU;IA2CxB;;;;;;;;;;OAUG;YACW,wBAAwB;IA4CtC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IAahB;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAgCzB;;OAEG;IACH,OAAO,CAAC,aAAa;CAUtB"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { SOURCE_LABELS } from '../memory/types.js';
|
|
2
|
+
import { logger } from '../logging/logger.js';
|
|
3
|
+
import { slugify } from '../utils/strings.js';
|
|
4
|
+
import { toError } from '../utils/errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* 用户画像管理器
|
|
7
|
+
*/
|
|
8
|
+
export class UserProfile {
|
|
9
|
+
index;
|
|
10
|
+
/** 内存缓存:启动时从 SQLite 全量加载 */
|
|
11
|
+
cache = new Map();
|
|
12
|
+
constructor(index) {
|
|
13
|
+
this.index = index;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 启动时从 SQLite 加载所有已确认的画像条目
|
|
17
|
+
*
|
|
18
|
+
* 存储中只保存已确认的条目(confirmed = true),
|
|
19
|
+
* 待确认条目仅存内存缓存,不写入存储。
|
|
20
|
+
*
|
|
21
|
+
* P2-5 content 字段使用 JSON 编码存储 category + value 元数据,
|
|
22
|
+
* 兼容旧格式(name 字段 "${category}: ${value}")作为降级路径。
|
|
23
|
+
*/
|
|
24
|
+
async load() {
|
|
25
|
+
const memories = this.index.getBySource(SOURCE_LABELS.PROFILE);
|
|
26
|
+
const entries = [];
|
|
27
|
+
for (const m of memories) {
|
|
28
|
+
// P2-5 优先从 content JSON 解码,降级到旧格式 name 解析
|
|
29
|
+
const parsed = this.parseContentField(m.content, m.name);
|
|
30
|
+
const entry = {
|
|
31
|
+
id: m.id,
|
|
32
|
+
category: parsed.category,
|
|
33
|
+
value: parsed.value,
|
|
34
|
+
source: '',
|
|
35
|
+
weight: m.score,
|
|
36
|
+
confirmed: true, // 存储中只保存已确认条目
|
|
37
|
+
updatedAt: m.accessedAt,
|
|
38
|
+
};
|
|
39
|
+
this.cache.set(entry.id, entry);
|
|
40
|
+
entries.push(entry);
|
|
41
|
+
}
|
|
42
|
+
logger.info({
|
|
43
|
+
total: entries.length,
|
|
44
|
+
confirmed: entries.filter((e) => e.confirmed).length,
|
|
45
|
+
pending: entries.filter((e) => !e.confirmed).length,
|
|
46
|
+
}, '用户画像加载完成');
|
|
47
|
+
return entries;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 实时归档:将提取的用户事实写入存储
|
|
51
|
+
*
|
|
52
|
+
* 每轮 chat() 结束后,由 Agent 调用 extractUserFacts() 提取事实后传入。
|
|
53
|
+
* 高置信度(≥0.8)→ 直接归档为 confirmed
|
|
54
|
+
* 低置信度 → 标记 confirmed = false,首次召回时 Agent 向用户确认
|
|
55
|
+
*
|
|
56
|
+
* @param facts 由 extractUserFacts() 提取的事实列表
|
|
57
|
+
*/
|
|
58
|
+
async archiveFacts(facts) {
|
|
59
|
+
if (facts.length === 0)
|
|
60
|
+
return 0;
|
|
61
|
+
let archived = 0;
|
|
62
|
+
for (const fact of facts) {
|
|
63
|
+
const entry = await this.upsertFact(fact);
|
|
64
|
+
if (entry)
|
|
65
|
+
archived++;
|
|
66
|
+
}
|
|
67
|
+
return archived;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 获取所有已确认的画像条目(system prompt 注入用)
|
|
71
|
+
*/
|
|
72
|
+
getConfirmed() {
|
|
73
|
+
return Array.from(this.cache.values()).filter((e) => e.confirmed);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 获取所有待确认的画像条目(供宿主 UI 展示确认/拒绝操作)
|
|
77
|
+
*
|
|
78
|
+
* 待确认条目仅存内存缓存(未写入存储),进程重启后丢失。
|
|
79
|
+
* 宿主应定期或在新对话后查询此方法,展示给用户确认。
|
|
80
|
+
*/
|
|
81
|
+
getPending() {
|
|
82
|
+
return Array.from(this.cache.values()).filter((e) => !e.confirmed);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 构建 system prompt 中的用户画像段
|
|
86
|
+
*
|
|
87
|
+
* 格式:
|
|
88
|
+
* 【用户画像】
|
|
89
|
+
* - 身份:张三,男,25岁,住北京
|
|
90
|
+
* - 偏好:TypeScript, Python, VS Code
|
|
91
|
+
* - 专长:后端开发,系统架构
|
|
92
|
+
* - 习惯:上午工作,下午思考
|
|
93
|
+
*/
|
|
94
|
+
buildSystemPrompt() {
|
|
95
|
+
const confirmed = this.getConfirmed();
|
|
96
|
+
if (confirmed.length === 0)
|
|
97
|
+
return '';
|
|
98
|
+
// 按分类聚合
|
|
99
|
+
const grouped = new Map();
|
|
100
|
+
for (const e of confirmed) {
|
|
101
|
+
const list = grouped.get(e.category) ?? [];
|
|
102
|
+
list.push(e.value
|
|
103
|
+
// "姓名: 张三" → "张三"
|
|
104
|
+
.replace(/^[^:]+:\s*/, ''));
|
|
105
|
+
grouped.set(e.category, list);
|
|
106
|
+
}
|
|
107
|
+
const lines = ['【用户画像】'];
|
|
108
|
+
for (const [cat, vals] of grouped) {
|
|
109
|
+
const label = this.categoryLabel(cat);
|
|
110
|
+
lines.push(`- ${label}:${vals.join(',')}`);
|
|
111
|
+
}
|
|
112
|
+
return lines.join('\n');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 确认待确认条目(用户在对话中确认了)
|
|
116
|
+
*
|
|
117
|
+
* 确认后写入存储(此前仅存内存缓存)
|
|
118
|
+
*
|
|
119
|
+
* @param id 条目 ID
|
|
120
|
+
*/
|
|
121
|
+
async confirm(id) {
|
|
122
|
+
const entry = this.cache.get(id);
|
|
123
|
+
if (!entry)
|
|
124
|
+
return;
|
|
125
|
+
entry.confirmed = true;
|
|
126
|
+
// 确认后写入存储(此前仅存内存缓存)
|
|
127
|
+
const memory = this.toMemory(entry);
|
|
128
|
+
this.index.upsert(memory);
|
|
129
|
+
logger.info({ id, category: entry.category, value: entry.value }, '用户画像条目已确认');
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 拒绝待确认条目(用户在对话中否认了)
|
|
133
|
+
*
|
|
134
|
+
* @param id 条目 ID
|
|
135
|
+
*/
|
|
136
|
+
async reject(id) {
|
|
137
|
+
this.cache.delete(id);
|
|
138
|
+
try {
|
|
139
|
+
this.index.delete(id);
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
// 索引中可能不存在(低置信度条目可能未写入):记录 debug 日志便于排查
|
|
143
|
+
logger.debug({ id, err: toError(err).message }, '索引删除失败(条目可能未写入索引)');
|
|
144
|
+
}
|
|
145
|
+
logger.info({ id }, '用户画像条目已删除(用户否认)');
|
|
146
|
+
}
|
|
147
|
+
// ── 私有方法 ──────────────────────────────────────
|
|
148
|
+
/**
|
|
149
|
+
* 写入单条事实到 SQLite
|
|
150
|
+
*
|
|
151
|
+
* 冲突解决策略:
|
|
152
|
+
* 同分类(identity/preference/expertise/habit/history)的新事实
|
|
153
|
+
* 会替换旧事实。因为用户画像是"当前状态"而非"历史记录"。
|
|
154
|
+
* 例:"我叫张三" → 后续说"我叫李四" → 只保留"李四",张三被移除。
|
|
155
|
+
*
|
|
156
|
+
* @returns 成功写入的条目,或 null(写入失败)
|
|
157
|
+
*/
|
|
158
|
+
async upsertFact(fact) {
|
|
159
|
+
// 构造稳定 ID(profile: 前缀 + 分类 + slug)
|
|
160
|
+
const id = `profile:user-profile-${fact.category}-${slugify(fact.value)}`;
|
|
161
|
+
// 同分类冲突解决 — 删除旧条目(相同子分类 + 不同值 = 用户更新了信息)
|
|
162
|
+
await this.removeConflictingEntries(fact);
|
|
163
|
+
const entry = {
|
|
164
|
+
id,
|
|
165
|
+
category: fact.category,
|
|
166
|
+
value: fact.value,
|
|
167
|
+
source: fact.sourceTurn,
|
|
168
|
+
weight: 1.0,
|
|
169
|
+
confirmed: fact.confidence >= 0.8, // 高置信度直接确认
|
|
170
|
+
updatedAt: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
try {
|
|
173
|
+
// 仅已确认条目写入存储(待确认条目仅存内存缓存)
|
|
174
|
+
if (entry.confirmed) {
|
|
175
|
+
const memory = this.toMemory(entry);
|
|
176
|
+
this.index.upsert(memory);
|
|
177
|
+
}
|
|
178
|
+
this.cache.set(id, entry);
|
|
179
|
+
if (entry.confirmed) {
|
|
180
|
+
logger.info({ id, category: fact.category, value: fact.value, confidence: fact.confidence }, '用户画像实时归档(已确认)');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
logger.info({ id, category: fact.category, value: fact.value, confidence: fact.confidence }, '用户画像待确认');
|
|
184
|
+
}
|
|
185
|
+
return entry;
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
logger.warn({ err, id, category: fact.category }, '用户画像归档失败');
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* 删除同分类的旧条目(用户更新了信息)
|
|
194
|
+
*
|
|
195
|
+
* 当用户说"我叫李四"替换之前的"我叫张三"时,移除旧的 identity 条目。
|
|
196
|
+
* 策略:同分类(category)下,新值替换旧值。判断标准是旧条目的 value 前缀。
|
|
197
|
+
*
|
|
198
|
+
* P2-5 从 content JSON 解码 category,替代 name 字段隐式解析。
|
|
199
|
+
* P2-3 构建 contentPrefix → entry 的 Map 索引,冲突检测从 O(n*m) 降为 O(m)。
|
|
200
|
+
*
|
|
201
|
+
* @param fact 当前提取到的新事实
|
|
202
|
+
*/
|
|
203
|
+
async removeConflictingEntries(fact) {
|
|
204
|
+
try {
|
|
205
|
+
const existing = this.index.getBySource(SOURCE_LABELS.PROFILE);
|
|
206
|
+
// 提取新事实的核心模式(如 "姓名: 李四" → 前缀 "姓名")
|
|
207
|
+
const newPrefix = (fact.value.split(':')[0] ?? '').trim();
|
|
208
|
+
// P2-3 构建 contentPrefix → Memory 的 Map 索引,冲突检测降为 O(m)
|
|
209
|
+
const prefixIndex = new Map();
|
|
210
|
+
for (const m of existing) {
|
|
211
|
+
// P2-5 从 content JSON 解码 category,替代 parseNameField
|
|
212
|
+
const parsed = this.parseContentField(m.content, m.name);
|
|
213
|
+
if (parsed.category !== fact.category)
|
|
214
|
+
continue;
|
|
215
|
+
const oldPrefix = (parsed.value.split(':')[0] ?? '').trim();
|
|
216
|
+
if (!oldPrefix)
|
|
217
|
+
continue;
|
|
218
|
+
const key = `${parsed.category}:${oldPrefix}`;
|
|
219
|
+
const list = prefixIndex.get(key);
|
|
220
|
+
if (list) {
|
|
221
|
+
list.push(m);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
prefixIndex.set(key, [m]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// 在索引中查找冲突条目
|
|
228
|
+
const conflictKey = `${fact.category}:${newPrefix}`;
|
|
229
|
+
const conflicts = prefixIndex.get(conflictKey);
|
|
230
|
+
if (conflicts) {
|
|
231
|
+
for (const m of conflicts) {
|
|
232
|
+
const parsed = this.parseContentField(m.content, m.name);
|
|
233
|
+
if (parsed.value !== fact.value) {
|
|
234
|
+
this.index.delete(m.id);
|
|
235
|
+
logger.info({ oldId: m.id, oldValue: parsed.value, newValue: fact.value }, '用户画像冲突已解决');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
// 冲突解决失败不阻塞写入
|
|
242
|
+
logger.debug({ err: toError(err).message }, '用户画像冲突解决失败');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* 将 UserProfileEntry 转为 Memory(用于写入 SQLite)
|
|
247
|
+
*
|
|
248
|
+
* P2-5 content 字段使用 JSON 编码存储 category + value 元数据,
|
|
249
|
+
* name 字段为固定可读标签,category 通过 content 的 JSON 元数据显式编码。
|
|
250
|
+
* 确认状态:仅已确认条目调用此方法(待确认条目不写入存储)
|
|
251
|
+
*/
|
|
252
|
+
toMemory(entry) {
|
|
253
|
+
const now = new Date().toISOString();
|
|
254
|
+
return {
|
|
255
|
+
id: entry.id,
|
|
256
|
+
content: JSON.stringify({ category: entry.category, value: entry.value }),
|
|
257
|
+
source: SOURCE_LABELS.PROFILE,
|
|
258
|
+
name: `用户画像-${entry.category}`,
|
|
259
|
+
createdAt: now,
|
|
260
|
+
accessedAt: entry.updatedAt || now,
|
|
261
|
+
score: entry.weight,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 从 content 字段解析 category 和 value
|
|
266
|
+
*
|
|
267
|
+
* P2-5 优先从 content JSON 解码元数据,降级到旧格式 name 字段解析,
|
|
268
|
+
* 确保已有 SQLite 数据(旧格式 name="${category}: ${value}")兼容加载。
|
|
269
|
+
*
|
|
270
|
+
* @param content Memory 的 content 字段(新格式为 JSON,旧格式为纯 value)
|
|
271
|
+
* @param name Memory 的 name 字段(旧格式为 "${category}: ${value}")
|
|
272
|
+
* @returns 解析出的 category 和 value
|
|
273
|
+
*/
|
|
274
|
+
parseContentField(content, name) {
|
|
275
|
+
// 优先尝试 JSON 解码(新格式)
|
|
276
|
+
try {
|
|
277
|
+
const parsed = JSON.parse(content);
|
|
278
|
+
if (parsed.category && parsed.value) {
|
|
279
|
+
const validCategories = ['identity', 'preference', 'expertise', 'habit', 'history'];
|
|
280
|
+
if (validCategories.includes(parsed.category)) {
|
|
281
|
+
return { category: parsed.category, value: parsed.value };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// content 不是 JSON,降级到旧格式
|
|
287
|
+
}
|
|
288
|
+
// 降级:从 name 字段解析(旧格式 "${category}: ${value}")
|
|
289
|
+
const idx = name.indexOf(':');
|
|
290
|
+
if (idx >= 0) {
|
|
291
|
+
const category = name.slice(0, idx).trim();
|
|
292
|
+
const validCategories = ['identity', 'preference', 'expertise', 'habit', 'history'];
|
|
293
|
+
if (validCategories.includes(category)) {
|
|
294
|
+
const value = name.slice(idx + 1).trim();
|
|
295
|
+
return { category, value: value || content };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// 最终降级:默认 identity 分类
|
|
299
|
+
return { category: 'identity', value: content };
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 分类标签
|
|
303
|
+
*/
|
|
304
|
+
categoryLabel(cat) {
|
|
305
|
+
const labels = {
|
|
306
|
+
identity: '身份',
|
|
307
|
+
preference: '偏好',
|
|
308
|
+
expertise: '专长',
|
|
309
|
+
habit: '习惯',
|
|
310
|
+
history: '历史',
|
|
311
|
+
};
|
|
312
|
+
return labels[cat];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=userProfile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userProfile.js","sourceRoot":"","sources":["../../src/memory/userProfile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 嵌入服务接口
|
|
3
|
+
* 向量存储依赖此接口生成文本嵌入向量
|
|
4
|
+
*
|
|
5
|
+
* batchEmbed 返回向量数组,顺序与输入一致。
|
|
6
|
+
* EmbeddingProvider(llm/embedding.ts)满足此接口(结构子类型)。
|
|
7
|
+
*/
|
|
8
|
+
export interface EmbeddingService {
|
|
9
|
+
embed(text: string): Promise<number[]>;
|
|
10
|
+
batchEmbed(texts: string[]): Promise<Array<{
|
|
11
|
+
text: string;
|
|
12
|
+
vector: number[];
|
|
13
|
+
}>>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 向量存储
|
|
17
|
+
*
|
|
18
|
+
* 纯 JS 实现,内存中维护向量索引,定期持久化到 JSON 文件
|
|
19
|
+
* 适用于单用户本地场景(5k 条记录以内)
|
|
20
|
+
*
|
|
21
|
+
* 依赖 EmbeddingService 接口(依赖倒置,与 llm/ 层解耦)
|
|
22
|
+
*/
|
|
23
|
+
export declare class VectorStore {
|
|
24
|
+
private readonly storePath;
|
|
25
|
+
private readonly embeddingProvider;
|
|
26
|
+
/** 内存中的向量索引 */
|
|
27
|
+
private entries;
|
|
28
|
+
/** 向量维度(由第一个插入的向量决定) */
|
|
29
|
+
private dimension;
|
|
30
|
+
/** 是否有未持久化的变更 */
|
|
31
|
+
private dirty;
|
|
32
|
+
constructor(storePath: string, embeddingProvider: EmbeddingService);
|
|
33
|
+
/**
|
|
34
|
+
* 从 JSON 文件加载向量索引(冷启动)
|
|
35
|
+
*/
|
|
36
|
+
load(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* 持久化向量索引到 JSON 文件
|
|
39
|
+
*/
|
|
40
|
+
save(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* 为文本生成向量并存储
|
|
43
|
+
* @param id 记忆 ID
|
|
44
|
+
* @param text 待嵌入的文本
|
|
45
|
+
*/
|
|
46
|
+
upsert(id: string, text: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* 批量嵌入并存储
|
|
49
|
+
* @param items ID + 文本对
|
|
50
|
+
*/
|
|
51
|
+
batchUpsert(items: Array<{
|
|
52
|
+
id: string;
|
|
53
|
+
text: string;
|
|
54
|
+
}>): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* 删除向量
|
|
57
|
+
*/
|
|
58
|
+
delete(id: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* 语义搜索:基于查询文本的向量,返回 topK 最相似的 ID
|
|
61
|
+
* @param query 查询文本
|
|
62
|
+
* @param topK 返回数量上限
|
|
63
|
+
* @param minSimilarity 最低相似度阈值(0~1)
|
|
64
|
+
* @returns ID + 相似度 对的数组,按相似度降序排列
|
|
65
|
+
*/
|
|
66
|
+
search(query: string, topK?: number, minSimilarity?: number): Promise<Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
similarity: number;
|
|
69
|
+
}>>;
|
|
70
|
+
/**
|
|
71
|
+
* 获取存储的向量数量
|
|
72
|
+
*/
|
|
73
|
+
get size(): number;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=vectorStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorStore.d.ts","sourceRoot":"","sources":["../../src/memory/vectorStore.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC9B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC,CAAC;CAClF;AAsBD;;;;;;;GAOG;AACH,qBAAa,WAAW;IAWpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAXpC,eAAe;IACf,OAAO,CAAC,OAAO,CAA+B;IAE9C,wBAAwB;IACxB,OAAO,CAAC,SAAS,CAAK;IAEtB,iBAAiB;IACjB,OAAO,CAAC,KAAK,CAAS;gBAGH,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,gBAAgB;IAGtD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB3B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASrD;;;OAGG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB5E;;OAEG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKxB;;;;;;OAMG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,IAAI,SAAI,EACR,aAAa,SAAM,GAClB,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAgBrD;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|