@aalis/plugin-user-relation 0.4.1

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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/dist/actions.d.ts +13 -0
  3. package/dist/actions.d.ts.map +1 -0
  4. package/dist/actions.js +705 -0
  5. package/dist/actions.js.map +1 -0
  6. package/dist/commands.d.ts +46 -0
  7. package/dist/commands.d.ts.map +1 -0
  8. package/dist/commands.js +601 -0
  9. package/dist/commands.js.map +1 -0
  10. package/dist/consolidate-llm.d.ts +150 -0
  11. package/dist/consolidate-llm.d.ts.map +1 -0
  12. package/dist/consolidate-llm.js +373 -0
  13. package/dist/consolidate-llm.js.map +1 -0
  14. package/dist/extractor.d.ts +308 -0
  15. package/dist/extractor.d.ts.map +1 -0
  16. package/dist/extractor.js +1356 -0
  17. package/dist/extractor.js.map +1 -0
  18. package/dist/index.d.ts +33 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +626 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/middleware.d.ts +41 -0
  23. package/dist/middleware.d.ts.map +1 -0
  24. package/dist/middleware.js +281 -0
  25. package/dist/middleware.js.map +1 -0
  26. package/dist/rename-watcher.d.ts +16 -0
  27. package/dist/rename-watcher.d.ts.map +1 -0
  28. package/dist/rename-watcher.js +16 -0
  29. package/dist/rename-watcher.js.map +1 -0
  30. package/dist/service.d.ts +1108 -0
  31. package/dist/service.d.ts.map +1 -0
  32. package/dist/service.js +4462 -0
  33. package/dist/service.js.map +1 -0
  34. package/dist/store.d.ts +89 -0
  35. package/dist/store.d.ts.map +1 -0
  36. package/dist/store.js +207 -0
  37. package/dist/store.js.map +1 -0
  38. package/dist/tools.d.ts +48 -0
  39. package/dist/tools.d.ts.map +1 -0
  40. package/dist/tools.js +1630 -0
  41. package/dist/tools.js.map +1 -0
  42. package/dist/types.d.ts +432 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +94 -0
  45. package/dist/types.js.map +1 -0
  46. package/dist/utils.d.ts +419 -0
  47. package/dist/utils.d.ts.map +1 -0
  48. package/dist/utils.js +1630 -0
  49. package/dist/utils.js.map +1 -0
  50. package/package.json +57 -0
package/dist/types.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * 人物关系图数据模型 —— 事件图 (Event-centric) 形态。
3
+ *
4
+ * 设计要点:
5
+ * - 单层 global 视图(跨平台 / 跨群聚合);按"来源"在 evidence 里记录细粒度溯源,
6
+ * 不再做 group/platform 物理隔离,避免 UI 切层与多份冗余更新带来的混淆。
7
+ * - Person 复用 plugin-user-profile 的 `platform:userId` 作为稳定身份。
8
+ * - Event 是一阶节点:群里被讨论的事件、作品、行为、事故、合作等都作为节点,
9
+ * 人通过 person-event 边参与其中。person-person 直连边只承载长期身份性关系
10
+ * (CP / 友 / 对手 / 师徒等),不承载临时事件参与。
11
+ * - 所有边都带 evidence[]:sourceQuote + messageIds,用于 webui 溯源与未来审计。
12
+ */
13
+ /**
14
+ * 人 → 人 关系类型 —— **半开放词表**。
15
+ *
16
+ * LLM 提取时会被推荐优先使用下列高频词,必要时可自创新词;
17
+ * 应用层 normalize 阶段会把同义词归一(best_friend → friend)。
18
+ */
19
+ export const RecommendedPersonRelationTypes = [
20
+ 'friend',
21
+ 'cp',
22
+ 'rival',
23
+ 'mentor',
24
+ 'colleague',
25
+ 'familiar',
26
+ 'antagonist',
27
+ 'admirer',
28
+ 'is-alias-of', // 「A 是 B 的别名 / 小号」(有向)
29
+ 'alt-account-of', // 「A 是 B 的小号」(有向)
30
+ ];
31
+ /**
32
+ * 人际层级维度 —— 与 `directed` 正交。
33
+ *
34
+ * `directed` 描述"A 声明与 B 的关系"(reporter 语义);`hierarchy` 单独描述
35
+ * 角色高低,避免把"上下/平级"塞进 relationType 文本里污染语义。
36
+ *
37
+ * - `superior`:from 视角下 from > to(如 from 是老板、师父、长辈)
38
+ * - `subordinate`:from < to
39
+ * - `peer`:明确平级(同学、同事、朋友)
40
+ * - `unknown`:未知或不适用(默认)
41
+ */
42
+ export const PersonHierarchyValues = ['superior', 'peer', 'subordinate', 'unknown'];
43
+ export const RecommendedPersonEntityRoles = [
44
+ 'enthusiast',
45
+ 'participant',
46
+ 'owner',
47
+ 'creator',
48
+ 'critic',
49
+ 'visitor',
50
+ 'mentioned',
51
+ ];
52
+ /**
53
+ * 事件 → 事件 的关联类型(推荐词表,允许自创小写英文短词)。
54
+ *
55
+ * - `caused-by`:A 由 B 引起(有方向)
56
+ * - `follows`:A 紧随 B 发生(有方向)
57
+ * - `related`:相关联(无方向)
58
+ * - `contradicts`:互相矛盾 / 抵消(无方向)
59
+ * - `part-of`:A 是 B 的一部分(有方向)
60
+ */
61
+ export const RecommendedEventEventRelationTypes = [
62
+ 'caused-by',
63
+ 'follows',
64
+ 'related',
65
+ 'contradicts',
66
+ 'part-of',
67
+ ];
68
+ /**
69
+ * 事件 → 实体 的关联类型(推荐词表,允许自创小写英文短词)。
70
+ *
71
+ * - `about`:事件讨论/关于该实体(如「讨论三角洲新赛季」 about 《三角洲》)
72
+ * - `uses`:事件使用该实体(如「直播」 uses 《三角洲》)
73
+ * - `located-at`:事件发生在某地点 / 场所
74
+ * - `produced`:事件产生了该实体(作品 / 产品)
75
+ */
76
+ export const RecommendedEventEntityRelationTypes = ['about', 'uses', 'located-at', 'produced', 'part-of'];
77
+ /**
78
+ * 实体 → 实体 的关联类型(推荐词表,允许自创)。常用于表达实体间的属于 / 包含 / 变体 / 对立 关系。
79
+ *
80
+ * - `part-of`:A 是 B 的一部分(有向),如「绝巴 part-of 三角洲」
81
+ * - `contains`:A 包含 B(有向,与 part-of 互为逆)
82
+ * - `variant-of`:A 是 B 的变体 / 资料片(有向)
83
+ * - `related`:相关(无向)
84
+ * - `opposite`:对立 / 互斥(无向)
85
+ */
86
+ export const RecommendedEntityEntityRelationTypes = [
87
+ 'part-of',
88
+ 'contains',
89
+ 'variant-of',
90
+ 'related',
91
+ 'opposite',
92
+ 'is-alias-of', // 「《绝巴》 is-alias-of 《绝密公司上巴谷》」(有向)
93
+ ];
94
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAsQH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,QAAQ;IACR,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,WAAW;IACX,UAAU;IACV,YAAY;IACZ,SAAS;IACT,aAAa,EAAE,uBAAuB;IACtC,gBAAgB,EAAE,kBAAkB;CAC5B,CAAC;AAIX;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,CAAU,CAAC;AA6D7F,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,YAAY;IACZ,aAAa;IACb,OAAO;IACP,SAAS;IACT,QAAQ;IACR,SAAS;IACT,WAAW;CACH,CAAC;AAoBX;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG;IAChD,WAAW;IACX,SAAS;IACT,SAAS;IACT,aAAa;IACb,SAAS;CACD,CAAC;AAmBX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,CAAU,CAAC;AAoBnH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG;IAClD,SAAS;IACT,UAAU;IACV,YAAY;IACZ,SAAS;IACT,UAAU;IACV,aAAa,EAAE,mCAAmC;CAC1C,CAAC"}
@@ -0,0 +1,419 @@
1
+ /**
2
+ * utils.ts —— RelationService 用到的纯函数 / 常量。
3
+ *
4
+ * 拆出动机:service.ts 原 3000+ 行,把不依赖 `this` 的模块级 helper(去重键、PageRank、
5
+ * 边邻接、名称归一化、别名合并启发式等)抽出来,让 service.ts 更聚焦于"类暴露的应用层 API"。
6
+ *
7
+ * 行为零变化:本文件函数全部来自 service.ts 的原模块级声明,原样搬运。
8
+ */
9
+ import type { CommunityMembership, EntityEntityEdge, EntityNode, EventEntityEdge, EventEventEdge, EventNode, EvidenceRef, PersonEntityEdge, PersonEventEdge, PersonPersonEdge, RelationEdge, RelationGraphSnapshot } from './types.js';
10
+ /**
11
+ * 合并实体别名:
12
+ * - 入参中空串/全空白/与 name 等价的项一律剔除(按 normalizeName 比较)
13
+ * - 与已有 alias 也按 normalizeName 去重(大小写、全半角、标点都标准化后比较,保留首次写法)
14
+ * - 总长度截断到 MAX_ALIASES_PER_ENTITY;超出部分**优先丢弃 incoming 里靠后的新加项**,
15
+ * 保留稳定的旧别名顺序,避免 LLM 反复输出新别名挤掉真有用的旧别名
16
+ *
17
+ * 若 incoming 为 undefined:返回 existing 的去重 + 截断版(顺手清掉历史脏数据)。
18
+ * 返回值长度为 0 时返回 undefined(避免落库一个空数组)。
19
+ */
20
+ export declare function mergeAliases(existing: string[] | undefined, incoming: string[] | undefined, primaryName?: string): string[] | undefined;
21
+ /**
22
+ * 人-事件角色优先级。同一 (person, event) 只保留最强角色的一条边:
23
+ * 发起者 > 参与者 > 被指向 > 转述者 > 旁观者。语义上强角色含盖弱角色。
24
+ */
25
+ export declare const PERSON_EVENT_ROLE_RANK: Record<PersonEventEdge['role'], number>;
26
+ /**
27
+ * 人-实体角色优先级。同一 (person, entity) 只保留最强角色。
28
+ * 热爱 > 创作者 > 拥有者 > 批评者 > 参与者 > 访问者 > 仅提及。
29
+ */
30
+ export declare const PERSON_ENTITY_ROLE_RANK: Record<PersonEntityEdge['role'], number>;
31
+ /**
32
+ * 给定边类型 + role/relationType,返回首次建边的默认权重。
33
+ * 未命中 → 走该 kind 的 `default`;person-event/person-entity 没有 default,
34
+ * 因为 role 是闭合枚举(按 RANK 已穷举),未命中说明上游类型错误,安全兜底 0.3。
35
+ */
36
+ export declare function roleDefaultWeight(kind: 'person-event', role: PersonEventEdge['role']): number;
37
+ export declare function roleDefaultWeight(kind: 'person-entity', role: PersonEntityEdge['role']): number;
38
+ export declare function roleDefaultWeight(kind: 'person-person' | 'event-event' | 'event-entity' | 'entity-entity', relationType: string): number;
39
+ /** 边邻接索引:供 BFS 复用,避免每次扫全表 */
40
+ export declare function buildAdjacency(edges: RelationEdge[]): {
41
+ peByPerson: Map<string, PersonEventEdge[]>;
42
+ ppByPerson: Map<string, PersonPersonEdge[]>;
43
+ peByEvent: Map<string, PersonEventEdge[]>;
44
+ pentByPerson: Map<string, PersonEntityEdge[]>;
45
+ pentByEntity: Map<string, PersonEntityEdge[]>;
46
+ eeByEvent: Map<string, EventEventEdge[]>;
47
+ eentByEvent: Map<string, EventEntityEdge[]>;
48
+ eentByEntity: Map<string, EventEntityEdge[]>;
49
+ ententByEntity: Map<string, EntityEntityEdge[]>;
50
+ };
51
+ /** 节点名称归一化:用于按名去重和别名匹配。
52
+ * 零风险规则(确定无歧义、不会错合):
53
+ * - NFKC 归一化:全角→半角、合字拆分(避免「ABC」与「ABC」不等)
54
+ * - trim + 压缩中间空白
55
+ * - 小写化(英文)
56
+ * - 去除外层装饰符号:中英文书名号《》「」『』【】〈〉、引号""''""''、括号()()[]、空格
57
+ * (这些只是"装饰",不改变指代——「《绝航》」与「绝航」是同一对象)
58
+ * - 内部空格也一并删除:中文为主的场景里 "吐槽 API 调用限流" 与 "吐槽API调用限流"
59
+ * 显然指同一事件;纯英文短语 "open ai" 与 "openai" 也合并到同一节点(影响有限)。
60
+ * 注意:不做后缀剥离(如「OL/手游/PC版」),那种语义合并交给 LLM verifyAliasPair。
61
+ */
62
+ export declare function normalizeName(name: string): string;
63
+ /** 计算两字符串的最长公共前缀(按 UTF-16 code unit,对中文足够稳定)。 */
64
+ export declare function commonPrefix(a: string, b: string): string;
65
+ /** weight 累积:增量按 (1 - weight) * delta 收敛,避免无限增长 */
66
+ export declare function reinforceWeight(prev: number, delta: number): number;
67
+ export declare function clamp01(x: number): number;
68
+ /**
69
+ * 时间衰减配置:用于把"原始 weight"换算成"当前有效 weight"。
70
+ *
71
+ * 设计动机:reinforceWeight 让 weight 单调累积(0.5→0.65→...→1.0),
72
+ * 多轮老化后图里会沉淀一批"高 weight 老节点 / 强边"占满配额、永不淘汰。
73
+ * 加上时间衰减让 weight 自然回退,反复被提及的关系靠新的强化撑起来,
74
+ * 而不再被提及的关系会逐渐退出 top-N / 淘汰受保护范围。
75
+ *
76
+ * Eager 模式(当前选择):每次 `evictByQuota` 入口先调用
77
+ * `RelationService.rewriteWeights`,把所有 event/entity/edge 的 raw `weight`
78
+ * 物理改写为 `effectiveWeight`、并把 `lastReinforcedAt` 推到 now(作为新的衰减基准)。
79
+ * 优点:
80
+ * - DB 字段始终反映"当下真实强度",便于调试 / 观察 / WebUI 展示
81
+ * - reinforceWeight 从已衰减的 raw 出发渐进恢复(0.3 → 0.37 → 0.43…),
82
+ * 不像 lazy 模式 raw 卡死在 1.0 时 reinforceWeight(1.0, δ)=1.0、effW 离散跳跃
83
+ * - "淘汰排序"与 lazy 等价(都按 effectiveWeight),无策略回退
84
+ *
85
+ * Lazy 备选(已弃):DB 存 raw 累积值,effectiveWeight 仅查询时算。
86
+ * 缺点:raw 卡死高位时 reinforce 无渐进感、跨时间快照难比较实际强度。
87
+ *
88
+ * `effectiveWeight()` 仍是核心函数:rewriteWeights 调用它做回写、
89
+ * scoring / sorting / eviction 在两次 rewrite 之间也照常调用它做"实时校正"。
90
+ *
91
+ * - `halfLifeDays <= 0`:不衰减(向后兼容;rewriteWeights 也会 short-circuit)
92
+ * - `halfLifeDays > 0`:half-life 后 effW = raw × 0.5,half-life × log2(1/floor) 后达到 floor 不再衰减
93
+ * - `floor`:衰减下限因子(默认 0.3),保护"老朋友"——再久不联系也保留 30% 强度
94
+ */
95
+ export interface WeightDecayCfg {
96
+ halfLifeDays: number;
97
+ floor: number;
98
+ }
99
+ /**
100
+ * 计算"当前有效 weight":raw × max(0.5^(days/halfLife), floor)。
101
+ *
102
+ * - halfLifeDays<=0:直接返回 raw(向后兼容)
103
+ * - 使用 max(factor, floor):衰减不会无限趋近 0,保留长期关系底色
104
+ */
105
+ export declare function effectiveWeight(raw: number | undefined, lastReinforcedAt: number, now: number, cfg: WeightDecayCfg): number;
106
+ /** 单实体保留最近 N 条 evidence(按 extractedAt DESC 截断 + 同 key 去重)
107
+ * 去重双键:
108
+ * 1) `sessionId|sorted(messageIds).join(',')` — 精确判同:同会话同批 messageIds 视为重复。
109
+ * 2) 内容合并:同 sessionId + 同 quote 且 messageIds **存在交集** → 合并为一条
110
+ * (messageIds 取并集,extractedAt 取较新者)。这覆盖「滑动窗口对同句重复抽取」场景,
111
+ * 但不会把完全不相交的同句条目(可能是不同时段不同人重复说)错误合并。
112
+ */
113
+ export declare function trimEvidence(list: EvidenceRef[]): EvidenceRef[];
114
+ /** incoming 是否被 existing 完全覆盖(同一批消息已记过)。
115
+ * 成立时调用方可跳过 reinforce,避免同事实被重复计权。
116
+ * 双键判定:
117
+ * - 精确:incoming.evidenceKey ∈ existing.evidenceKey
118
+ * - 内容:存在同 sessionId+quote 的 existing 条目,且 messageIds 有交集
119
+ * incoming 为空时返回 false(保留原有「无 evidence 仍允许动作」语义)。
120
+ */
121
+ export declare function isEvidenceFullyCovered(incoming: EvidenceRef[], existing: EvidenceRef[]): boolean;
122
+ export declare function normalizeRelationType(input: string): string;
123
+ export declare function isSymmetricRelation(relationType: string): boolean;
124
+ export declare function isDirectedEventEventRelation(relationType: string): boolean;
125
+ export declare function isDirectedEntityEntityRelation(relationType: string): boolean;
126
+ /** description 裁剪:去首尾空白、限长 40 字,空串返回 undefined */
127
+ export declare function trimDescription(d: string | undefined): string | undefined;
128
+ export declare function isAliasMarkerEdge(e: RelationEdge): boolean;
129
+ /** 判断边是否在任意字段引用了某 id(覆盖 6 种 edge kind) */
130
+ export declare function edgeReferences(e: RelationEdge, id: string): boolean;
131
+ export declare function edgeInvolvesBoth(e: RelationEdge, a: string, b: string): boolean;
132
+ /**
133
+ * 给定一条边和"我方 nodeId",解析出"对端 id + 对端 kind + 我方是否为 to 端(incoming)"。
134
+ * 不匹配(边不引用 nodeId)时返回 null。
135
+ *
136
+ * 用途:聚合邻居(区分人物/事件/实体)、计算入边权重时复用统一逻辑,
137
+ * 避免各处用 `(e as any).to ?? (e as any).toId` 这类基于"虚构字段名"的脆弱访问
138
+ * (RelationEdge 的字段都有 kind 后缀,如 fromPersonId/toEventId,没有裸 to/from/toId/fromId)。
139
+ */
140
+ export declare function getEdgeOtherEnd(e: RelationEdge, nodeId: string): {
141
+ otherId: string;
142
+ otherKind: 'person' | 'event' | 'entity';
143
+ isIncoming: boolean;
144
+ } | null;
145
+ export declare function isAliasEdgeDirectionCorrect(e: RelationEdge, aliasId: string, canonicalId: string): boolean;
146
+ export declare function flipDirectedEdge(e: RelationEdge, aliasId: string, canonicalId: string): RelationEdge | null;
147
+ /** 把边中任一等于 aliasId 的字段替换为 canonicalId,返回浅拷贝 */
148
+ export declare function rewriteEdgeIds(e: RelationEdge, aliasId: string, canonicalId: string): RelationEdge;
149
+ export declare function isEdgeSelfLoop(e: RelationEdge): boolean;
150
+ /** 边的去重键(用于合并冲突检测)。无向边按字典序规范化端点。 */
151
+ export declare function edgeDedupKey(e: RelationEdge): string;
152
+ /** 合并两条同 dedupKey 的边:保留 keeper.id,合并 evidence、weight 取强化、时间取较新 */
153
+ export declare function mergeTwoEdges<T extends RelationEdge>(keeper: T, incoming: T): T;
154
+ /** 启发式:决定真正的 (alias, canonical) 方向。返回 null 表示无需翻转。 */
155
+ export declare function chooseCanonicalDirection(snapshot: RelationGraphSnapshot, aId: string, bId: string, kind: 'person' | 'entity' | 'event'): {
156
+ alias: string;
157
+ canonical: string;
158
+ } | null;
159
+ /**
160
+ * 标准 PageRank(带个性化向量),用于淘汰打分。
161
+ *
162
+ * - 把所有节点(人/事件/实体)放进同一张图;边权重取 `edge.weight`(最低 0.05)。
163
+ * - 无向边(is-alias-of 之外的 person-person/entity-entity directed=false)双向传播;
164
+ * directed=true 边只按 from→to 传播。
165
+ * - 个性化向量按 kind 分配种子权重(默认 人=3 / 物=2 / 事=1),从而"重要性 人>物>事"
166
+ * 不需要硬编码到打分,而是体现在 PR 的偏置上:人物附近的事件/实体 PR 更高。
167
+ * - 迭代到 L1 误差 < epsilon 或达到 maxIter 终止。
168
+ */
169
+ export declare function computePageRank(snap: RelationGraphSnapshot, opts: {
170
+ damping: number;
171
+ maxIter: number;
172
+ epsilon: number;
173
+ personSeed: number;
174
+ entitySeed: number;
175
+ eventSeed: number;
176
+ /**
177
+ * person→event / person→entity 单向边反向虚拟边的权重系数。
178
+ * 0 = 不加反向边(无 person-person 边的人 PR 退化到 seed 常数)。
179
+ * 默认 0.5:让“参与重要事件 / 关注热门实体”的人 PR 拉开差距,
180
+ * 同时避免事件 hub 过度反哺导致 PR 被少数几个红人垄断。
181
+ */
182
+ reverseEdgeFactor?: number;
183
+ /**
184
+ * 是否启用 component-size 缩放(Component-weighted Personalized PageRank):
185
+ * PR_final[i] = PR_raw[i] * sqrt(componentSize[i] / n),再重新归一化。
186
+ * 默认 true。
187
+ *
188
+ * 动机:反向虚拟边 + 闭环让"1 人 1 物 1 事"这类孤立小子图(如三角)
189
+ * 在 PR 上被相对高估——三个节点 mass 内循环、外面没有大节点稀释。
190
+ * 在淘汰打分 / profile 注入排序场景里,这种小圈子不应被高估为重要节点。
191
+ *
192
+ * 缩放只改变 component 之间的相对权重,component 内部的 PR 比例完全保留。
193
+ * 关闭则退化为标准 Personalized PageRank。
194
+ */
195
+ componentScale?: boolean;
196
+ }): Map<string, number>;
197
+ /**
198
+ * 计算 modularity Q ∈ [-0.5, 1)。Q > 0.3 通常认为社群结构清晰;Q < 0.1 几乎是随机划分。
199
+ *
200
+ * 公式:Q = (1/2m) Σ_ij [A_ij - k_i k_j / 2m] · δ(c_i, c_j)
201
+ * 实现:按社群内边权和 Σ_in 和社群总度 Σ_tot 聚合,等价为
202
+ * Q = Σ_c [ Σ_in(c) / 2m - (Σ_tot(c) / 2m)^2 ]
203
+ */
204
+ export declare function computeModularity(snap: RelationGraphSnapshot, communityMap: Map<string, string>): number;
205
+ /**
206
+ * 按图规模自适应推导 Louvain/Leiden 的分辨率 γ。
207
+ *
208
+ * 公式:γ = clamp(0.6, 2.5, 0.5 + log10(n / 30)),其中 n = snap.persons.length。
209
+ * - n ≤ 30 → 0.6(地板,小图保持粗粒度,避免每人一个社群)
210
+ * - n = 100 → ≈1.02(接近标准 Louvain)
211
+ * - n = 150 → ≈1.20(解决我们当前 36 人巨型社群被过度合并的问题)
212
+ * - n = 500 → ≈1.72
213
+ * - n ≥ 750 → 2.5(天花板,避免极细碎导致 c0~c100 难以消费)
214
+ *
215
+ * 背景:标准 Louvain(γ=1)存在 "resolution limit"(Fortunato & Barthélemy 2007)——
216
+ * 节点数越多越倾向于把小社群合并成超级社群。让 γ 随 n 单调微增是文献推荐做法。
217
+ *
218
+ * 不依赖边数 / 平均度:实现简单、可解释,对当前 < 1000 节点的图足够;如果后续图规模或密度
219
+ * 差异显著(比如某 scope 节点很少但边很密),再升级到 sqrt(2m/(n·d_target)) 的密度感知公式。
220
+ *
221
+ * persons 为空 → 返回 1.0(标准默认,安全兜底)。
222
+ */
223
+ export declare function computeAdaptiveResolution(snap: RelationGraphSnapshot): number;
224
+ /**
225
+ * Louvain 社群发现(无向加权图,单次 coarsening)。
226
+ *
227
+ * 适用场景:在 PageRank 算完后顺手把节点聚类成"小圈子"——
228
+ * - 群里有几个核心团体
229
+ * - 某人最常一起出现的是谁
230
+ *
231
+ * 实现要点:
232
+ * - 把全图视为无向加权图:所有边权重双向叠加;有向边只在 from→to 方向加权一次,无向边两端各加一次。
233
+ * - 阶段 1:局部移动——每个节点尝试加入邻居社群,按 modularity 增益 ΔQ 贪心选最大;扫一轮无改进即收敛。
234
+ * - 阶段 2:coarsening——把社群当超节点,社群间边权聚合,再跑一轮局部移动(标准 Louvain 多轮,
235
+ * 实测两轮已经稳定;我们的图 < 1000 节点,再多收益边际递减)。
236
+ * - 返回 `nodeId → communityId` 映射,communityId 是字符串(c0/c1/...)。
237
+ *
238
+ * 复杂度:O(E · iter),iter ≤ 10。对 360 节点几乎 instant。
239
+ *
240
+ * 不做:
241
+ * - 不返回 modularity 值(请用独立的 computeModularity)
242
+ * - resolution(γ)参数:默认 1.0(标准 Louvain);> 1 → 划得更细更多社群;< 1 → 划得更粗更少社群。
243
+ * 实现:把 ΔQ 公式里的 `kii * sigmaTot(C) / 2m` 项乘以 γ(标准做法,对应 RB 多分辨率模块度)。
244
+ * 常用范围:0.5 ~ 3.0。极端值(< 0.1 / > 10)会导致全图一个社群 / 每节点自成社群。
245
+ */
246
+ export declare function computeLouvain(snap: RelationGraphSnapshot, opts?: {
247
+ maxIterPerPass?: number;
248
+ minImprovement?: number;
249
+ resolution?: number;
250
+ }): Map<string, string>;
251
+ /**
252
+ * Leiden 社群发现(实用简化版:Louvain local-move + connectivity-based refinement)。
253
+ *
254
+ * ⚠️ **不是论文版完整 Leiden**:论文版 Leiden(Traag et al. 2019)含三阶段——
255
+ * 1. local move(同 Louvain)
256
+ * 2. refinement:在每个社群内部跑 modularity-weighted singleton subset move(随机走子集)
257
+ * 3. aggregation 时只压缩 refinement 后的子集
258
+ * 论文版能保证「γ-separation」+「γ-connection」严格性质,但实现 ~300 行。
259
+ *
260
+ * **本实现简化为**:
261
+ * 1. local move(同 Louvain)
262
+ * 2. refinement:对每个 Louvain 社群做 BFS 连通分量检测,把内部不连通的社群拆成多个子社群
263
+ * 3. (省略 aggregation 第二轮,直接返回 refined 结果)
264
+ *
265
+ * **解决了 Louvain 最大的诟病**——社群内部可能不连通("badly connected communities")。
266
+ * 在我们这种密度较高、规模 < 1000 的关系图上,质量提升足够明显,又不需要论文版的复杂度。
267
+ *
268
+ * Agent 视角:当怀疑 Louvain 把两群明显没交集的人分到同一社群时,换 leiden 跑一次能看到更细的划分。
269
+ */
270
+ export declare function computeLeiden(snap: RelationGraphSnapshot, opts?: {
271
+ maxIterPerPass?: number;
272
+ minImprovement?: number;
273
+ resolution?: number;
274
+ }): Map<string, string>;
275
+ /**
276
+ * SLPA — Speaker-Listener Label Propagation Algorithm(原生重叠社区发现)。
277
+ *
278
+ * 论文:Xie, Szymanski, Liu (2011) "SLPA: Uncovering Overlapping Communities in
279
+ * Social Networks via a Speaker-Listener Interaction Dynamic Process"。
280
+ *
281
+ * **与 Louvain/Leiden 的关键差别**:Louvain 是硬划分(每个节点恰好属于一个社群),
282
+ * SLPA 是软划分(节点可同时属于多个社群,按隶属度排序)。适合社交图里"残龙在全性基地+Aalis 周边
283
+ * 都活跃"这种跨群人物——硬划分会丢失次社群信息,SLPA 直接给出 `{c2: 0.62, c4: 0.31, c1: 0.07}`。
284
+ *
285
+ * 算法骨架(论文原版,未做加权扩展时):
286
+ * 1. 每个节点初始化一个 label memory:`{自身id: 1}`
287
+ * 2. 共 T 轮迭代;每轮按节点顺序:
288
+ * a. 选当前节点为 listener
289
+ * b. 它的每个邻居都作为 speaker,按 speaker 自己 memory 中的频率分布**随机抽**一个 label 吐出
290
+ * c. listener 收齐所有邻居吐的 label,按"票数最高"挑一个加进自己 memory(计数 +1)
291
+ * 3. 后处理:每个节点 memory 中频率 ≥ r·(T+1) 的 label 才保留为它的社群隶属;
292
+ * 然后按"出现次数"归一化为权重 ∈ (0, 1],按 weight 降序排列。
293
+ *
294
+ * **本实现的加权扩展**(默认开启,`weightedSpeaker=true`):
295
+ * - speaker 抽样时:按邻居边权 `w` 对其 memory 频率加权(边越重的邻居"声音越大")
296
+ * - listener 计票时:每张票按边权计数(不是 +1 而是 +w),同样让重边邻居有更高影响力
297
+ * - 这与本仓库带权图(edge.weight ∈ [0.05, 1.0])天然契合;纯无权图退化为论文原版
298
+ *
299
+ * **复杂度**:O(N · avgDeg · T)。对 400 节点 + T=20 几乎 instant;< 1000 节点都可放心用。
300
+ *
301
+ * **确定性**:内置 mulberry32 伪随机种子(由 node id 串字典序导出),跨进程同一 snapshot 输出
302
+ * 完全可复现;避免 Math.random 让 evictByQuota 每次结果都漂移。
303
+ *
304
+ * **不做**:
305
+ * - 不做社群间合并 / 拆分(论文里的 post-merge 步骤);阈值 r 已能调粒度
306
+ * - 不返回 modularity(重叠社区的 modularity 没有标准定义;想看质量看 `bridges` 跨社群占比)
307
+ *
308
+ * @returns nodeId → CommunityMembership[](按 weight 降序);空图返回空 Map
309
+ */
310
+ export declare function computeSlpa(snap: RelationGraphSnapshot, opts?: {
311
+ /** 迭代轮数 T,默认 20。论文实测 20 已对 < 1000 节点稳定收敛;增大无明显收益。 */
312
+ iterations?: number;
313
+ /** 频率阈值 r ∈ [0, 0.5],默认 0.1。频率 < r·(T+1) 的 label 会被剔除(噪声过滤);r 越大社群越纯,重叠越少。 */
314
+ threshold?: number;
315
+ /** 是否启用加权 speaker 抽样 + 加权 listener 计票,默认 true。带权图建议开。 */
316
+ weightedSpeaker?: boolean;
317
+ }): Map<string, CommunityMembership[]>;
318
+ /**
319
+ * 把若干个"语义同一对象"的 pair 按并查集合并成簇。
320
+ *
321
+ * 输入:LLM 已判 yes 的 pair 列表({aId, bId})。
322
+ * 输出:`Map<rootId, Set<memberId>>`;同一 root 下所有 id 在同一簇。
323
+ *
324
+ * 自然解决传递闭包:A↔B yes & B↔C yes ⇒ {A,B,C} 一簇。
325
+ * size<2 的簇(孤立 id)也会出现(如果某 id 只出现在自身),调用方按需过滤。
326
+ *
327
+ * 实现:路径压缩 + 按 rank 启发式合并,O(α(n)) 近似常数。
328
+ */
329
+ export declare function clusterEntitiesByPairs(yesPairs: ReadonlyArray<{
330
+ aId: string;
331
+ bId: string;
332
+ }>): Map<string, Set<string>>;
333
+ /**
334
+ * 在一个簇内挑选 canonical(合并后保留的代表)。
335
+ *
336
+ * 打分公式("合并专用",**不复用 compositeScore**,因为后者含 recency 偏向新节点):
337
+ * `mergeScore = 0.5·weightSum + 0.3·edgeCount + 0.2·evidenceCount`,
338
+ * 三项各自按"簇内 max"归一化到 [0,1]。
339
+ *
340
+ * 语义:信息越丰富(关系密、权值高、evidence 多)越当代表。
341
+ * 平局规则:分数并列时取 id 字典序最小者(稳定可复现)。
342
+ *
343
+ * @param members 簇内成员 id 集合
344
+ * @param entityById 实体 id → EntityNode 映射(用于查 evidence 数量)
345
+ * @param edgeStats 实体 id → {weightSum, edgeCount}(由调用方一次扫边表得到)
346
+ * @returns canonical 的 id;簇为空时返回 ''(调用方应过滤 size<2 簇,不应触发)
347
+ */
348
+ export declare function pickCanonicalByMergeScore(members: ReadonlySet<string>, entityById: ReadonlyMap<string, EntityNode>, edgeStats: ReadonlyMap<string, {
349
+ weightSum: number;
350
+ edgeCount: number;
351
+ }>): string;
352
+ /**
353
+ * 一次扫边表,为每个 entity 节点聚合 weightSum + edgeCount,供 pickCanonicalByMergeScore 使用。
354
+ *
355
+ * 统计范围:所有涉及 entity 的边(entity-entity 两端均计入;person-entity / event-entity 的 entity 端计入)。
356
+ * Person/event 节点不需要聚合(不会作为合并 canonical 候选)。
357
+ */
358
+ export declare function computeEntityEdgeStats(edges: ReadonlyArray<RelationEdge>): Map<string, {
359
+ weightSum: number;
360
+ edgeCount: number;
361
+ }>;
362
+ /**
363
+ * 余弦相似度。两个向量长度必须一致,返回 [-1, 1];任一为 0 向量返回 0。
364
+ * consolidate event 阶段用于 embedding-based 文本相似度。
365
+ */
366
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
367
+ /**
368
+ * 字符级 Jaccard:以 Unicode 字符(非字节)建集合,返回 |A∩B| / |A∪B|。
369
+ * 用于无 embedding 服务时的 fallback 文本相似度(对中文友好,比 token 化更稳)。
370
+ * 自动 normalizeName(去空白/小写/全半角合并),空串返回 0。
371
+ */
372
+ export declare function jaccardChars(a: string, b: string): number;
373
+ /**
374
+ * 计算两个 event 的字符级 Jaccard。专用于 consolidate 候选评估:
375
+ * - title 必算(normalize 后通常很短,含义稳定);
376
+ * - summary 仅在**两边都有**时参与加权:fused = 0.6·titleJac + 0.4·summaryJac;
377
+ * - 任一方缺 summary → 退化为 titleJac,避免"一方有长 summary、一方空"导致并集被
378
+ * 单侧 token 拉大、相似度被人为压低(这是历史上同会话同主题事件未被合并的主因)。
379
+ *
380
+ * 这里把 title/summary 分开算,比 `jaccardChars('${title} ${summary}', '${title} ${summary}')`
381
+ * 更稳定:原写法把 title 字符稀释到 summary 池里,标题完全相同时也会被低估。
382
+ */
383
+ export declare function eventPairJaccard(a: {
384
+ title: string;
385
+ summary?: string;
386
+ }, b: {
387
+ title: string;
388
+ summary?: string;
389
+ }): number;
390
+ /**
391
+ * 计算 EventNode embedding 的指纹(title + summary 的 sha1 前 16 hex)。
392
+ * 当节点的 title/summary 发生变化时,hash 自动变 → consolidate 阶段触发重新 embed。
393
+ * 使用 fnv1a + djb2 组合的 64bit 简化版(避免在浏览器/node 都依赖 crypto)。
394
+ */
395
+ export declare function computeEventEmbeddingHash(title: string, summary?: string): string;
396
+ /**
397
+ * 计算 EntityNode embedding 的指纹(entityKind + name + summary 的 fnv1a+djb2 32 hex)。
398
+ * 当 entityKind / name / summary 任一变化时,hash 自动变 → consolidate 阶段触发重新 embed。
399
+ * entityKind 加入 hash 是有意为之:同名跨 kind 视为不同实体,各自独立 embed。
400
+ */
401
+ export declare function computeEntityEmbeddingHash(name: string, summary?: string, entityKind?: string): string;
402
+ /**
403
+ * 一次扫边表,为每个 event 节点聚合 weightSum + edgeCount,供 pickCanonicalForEvents 使用。
404
+ * 统计范围:所有涉及 event 的边(event-event 两端均计入;person-event / event-entity 的 event 端计入)。
405
+ */
406
+ export declare function computeEventEdgeStats(edges: ReadonlyArray<RelationEdge>): Map<string, {
407
+ weightSum: number;
408
+ edgeCount: number;
409
+ }>;
410
+ /**
411
+ * 在一个 event 簇内挑选 canonical(合并后保留的代表)。
412
+ * 算法与 pickCanonicalByMergeScore 一致:mergeScore = 0.5·weightSum + 0.3·edgeCount + 0.2·evidenceCount。
413
+ * 平局取 id 字典序最小者。
414
+ */
415
+ export declare function pickCanonicalForEvents(members: ReadonlySet<string>, eventById: ReadonlyMap<string, EventNode>, edgeStats: ReadonlyMap<string, {
416
+ weightSum: number;
417
+ edgeCount: number;
418
+ }>): string;
419
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}