koishi-plugin-chatluna-affinity 0.1.2 → 0.1.3

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/lib/index.d.ts CHANGED
@@ -69,7 +69,7 @@ export interface Config {
69
69
  variableName: string;
70
70
  items: string[];
71
71
  };
72
- groupList: {
72
+ groupInfo: {
73
73
  enabled: boolean;
74
74
  variableName: string;
75
75
  includeMemberCount: boolean;
package/lib/index.js CHANGED
@@ -516,7 +516,7 @@ function apply(ctx, config) {
516
516
  return lines.join('\n');
517
517
  };
518
518
 
519
- const createGroupListProvider = (config) => async (_, __, configurable) => {
519
+ const createGroupInfoProvider = (config) => async (_, __, configurable) => {
520
520
  const session = configurable?.session;
521
521
  if (!session) return '暂无群信息。';
522
522
  if (!session.guildId) return '';
@@ -582,6 +582,18 @@ function apply(ctx, config) {
582
582
  }).flat();
583
583
  };
584
584
 
585
+ const resolveRandomDefaults = (randomConfig = {}) => {
586
+ const candidateMin = Number(randomConfig.min);
587
+ const candidateMax = Number(randomConfig.max);
588
+ const hasMin = Number.isFinite(candidateMin);
589
+ const hasMax = Number.isFinite(candidateMax);
590
+ const fallbackMin = hasMin ? candidateMin : hasMax ? candidateMax : 0;
591
+ const fallbackMax = hasMax ? candidateMax : hasMin ? candidateMin : 100;
592
+ const lower = Math.min(fallbackMin, fallbackMax);
593
+ const upper = Math.max(fallbackMin, fallbackMax);
594
+ return { min: lower, max: upper };
595
+ };
596
+
585
597
  const stripAtPrefix = (value) => {
586
598
  const text = String(value ?? '').trim();
587
599
  if (!text) return '';
@@ -775,9 +787,16 @@ function apply(ctx, config) {
775
787
  return { userId: fallback, nickname: fallback };
776
788
  };
777
789
 
778
- const createRandomProvider = () => async (args) => {
790
+ const createRandomProvider = (randomConfig) => async (args) => {
779
791
  const values = parseRandomArguments(args ?? []);
780
- if (!values.length) return '';
792
+ if (!values.length) {
793
+ const defaults = resolveRandomDefaults(randomConfig);
794
+ if (!Number.isFinite(defaults.min) || !Number.isFinite(defaults.max)) return '';
795
+ if (defaults.min === defaults.max) return String(Math.round(defaults.min));
796
+ const span = defaults.max - defaults.min;
797
+ const result = defaults.min + Math.round(Math.random() * span);
798
+ return String(result);
799
+ }
781
800
 
782
801
  if (values.length === 2 && typeof values[0] === 'number' && typeof values[1] === 'number') {
783
802
  const min = Math.min(values[0], values[1]);
@@ -901,15 +920,15 @@ function apply(ctx, config) {
901
920
  if (randomConfig.enabled !== false) {
902
921
  const variableName = String(randomConfig.variableName || 'random').trim();
903
922
  if (variableName) {
904
- ctx.chatluna.promptRenderer.registerFunctionProvider(variableName, createRandomProvider());
923
+ ctx.chatluna.promptRenderer.registerFunctionProvider(variableName, createRandomProvider(randomConfig));
905
924
  }
906
925
  }
907
926
 
908
- const groupListConfig = config.groupList || config.otherVariables?.groupList || {};
909
- if (groupListConfig.enabled) {
910
- const variableName = String(groupListConfig.variableName || 'groupList').trim();
927
+ const groupInfoConfig = config.groupInfo || config.otherVariables?.groupInfo || {};
928
+ if (groupInfoConfig.enabled) {
929
+ const variableName = String(groupInfoConfig.variableName || 'groupInfo').trim();
911
930
  if (variableName) {
912
- ctx.chatluna.promptRenderer.registerFunctionProvider(variableName, createGroupListProvider(groupListConfig));
931
+ ctx.chatluna.promptRenderer.registerFunctionProvider(variableName, createGroupInfoProvider(groupInfoConfig));
913
932
  }
914
933
  }
915
934
 
@@ -1380,6 +1399,20 @@ function apply(ctx, config) {
1380
1399
  if (removed) return `已解除 ${platform}/${normalizedUserId} 的自动黑名单。`;
1381
1400
  return `${platform}/${normalizedUserId} 不在自动黑名单中。`;
1382
1401
  });
1402
+
1403
+ ctx.command('affinity.groupList', '显示机器人已加入的群聊', { authority: 2 })
1404
+ .alias('群聊列表')
1405
+ .action(async ({ session }) => {
1406
+ if (!session) return '无法获取会话信息。';
1407
+ if (session.platform !== 'onebot') return '该指令仅支持 OneBot/NapCat 平台。';
1408
+ const list = await fetchGroupList(session);
1409
+ if (!list || !list.length) return '暂无群聊数据。';
1410
+ const groupInfoConfig = config.groupInfo || config.otherVariables?.groupInfo || {};
1411
+ return normalizeGroupList(list, {
1412
+ includeMemberCount: groupInfoConfig.includeMemberCount !== false,
1413
+ includeCreateTime: groupInfoConfig.includeCreateTime !== false
1414
+ });
1415
+ });
1383
1416
  }
1384
1417
 
1385
1418
  module.exports = { apply, Config, inject, name };
package/lib/schema.js CHANGED
@@ -7,10 +7,11 @@ const inject = {
7
7
  optional: ['puppeteer']
8
8
  };
9
9
 
10
- const createVariableEntry = (defaultName, description) =>
10
+ const createVariableEntry = (defaultName, description, extra = {}) =>
11
11
  Schema.object({
12
12
  enabled: Schema.boolean().default(true).description('是否启用该变量'),
13
- variableName: Schema.string().default(defaultName).description('变量名称')
13
+ variableName: Schema.string().default(defaultName).description('变量名称'),
14
+ ...extra
14
15
  })
15
16
  .description(description)
16
17
  .collapse();
@@ -208,21 +209,24 @@ const OtherVariablesSchema = Schema.object({
208
209
  })
209
210
  .description('机器人信息变量')
210
211
  .collapse(),
211
- groupList: Schema.object({
212
- enabled: Schema.boolean().default(false).description('是否启用群列表变量'),
213
- variableName: Schema.string().default('groupList').description('变量名称'),
212
+ groupInfo: Schema.object({
213
+ enabled: Schema.boolean().default(false).description('是否启用群信息变量'),
214
+ variableName: Schema.string().default('groupInfo').description('变量名称'),
214
215
  includeMemberCount: Schema.boolean().default(true).description('是否包含成员数量'),
215
216
  includeCreateTime: Schema.boolean().default(true).description('是否包含创建时间')
216
217
  })
217
- .description('群列表变量')
218
+ .description('群信息变量')
218
219
  .collapse(),
219
- random: createVariableEntry('random', '随机数变量')
220
+ random: createVariableEntry('random', '随机数变量', {
221
+ min: Schema.number().default(0).description('默认随机数下限'),
222
+ max: Schema.number().default(100).description('默认随机数上限')
223
+ })
220
224
  })
221
225
  .default({
222
226
  userInfo: { enabled: true, variableName: 'userInfo', items: [...defaultMemberInfoItems] },
223
227
  botInfo: { enabled: true, variableName: 'botInfo', items: [...defaultMemberInfoItems] },
224
- groupList: { enabled: false, variableName: 'groupList', includeMemberCount: true, includeCreateTime: true },
225
- random: { enabled: true, variableName: 'random' }
228
+ groupInfo: { enabled: false, variableName: 'groupInfo', includeMemberCount: true, includeCreateTime: true },
229
+ random: { enabled: true, variableName: 'random', min: 0, max: 100 }
226
230
  })
227
231
  .description('其他变量');
228
232
 
@@ -254,7 +258,7 @@ const OneBotToolsSchema = Schema.object({
254
258
  enablePokeTool: Schema.boolean().default(false).description('注册 ChatLuna 工具:戳一戳'),
255
259
  pokeToolName: Schema.string().default('poke_user').description('ChatLuna 工具名称:戳一戳'),
256
260
  enableSetSelfProfileTool: Schema.boolean().default(false).description('注册 ChatLuna 工具:修改自身账户信息'),
257
- setSelfProfileToolName: Schema.string().default('set_self_profile').description('ChatLuna 工具名称:修改自身账户信息'),
261
+ setSelfProfileToolName: Schema.string().default('set_self_profile').description('ChatLuna 工具名称:修改自身账户信息(支持昵称/签名/性别)'),
258
262
  enableDeleteMessageTool: Schema.boolean().default(false).description('注册 ChatLuna 工具:撤回消息'),
259
263
  deleteMessageToolName: Schema.string().default('delete_msg').description('ChatLuna 工具名称:撤回消息')
260
264
  }).description('其他工具');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-chatluna-affinity",
3
3
  "description": "为 ChatLuna Character 提供 {好感度}、{关系}、{日程} 等变量并提供对应的工具调用和低好感自动拉黑功能。",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md DELETED
@@ -1,123 +0,0 @@
1
- # koishi-plugin-chatluna-affinity
2
-
3
- 在 ChatLuna 中按用户维度维护“好感度”与“关系”状态,并提供可操作的工具与变量。
4
-
5
- ## 亮点一览
6
-
7
- - `affinity()` 变量:随时取得用户与机器人的好感度。初次使用会自动初始化并写入数据库。
8
- - `relationship()` 变量:返回友好度对应的称谓,支持自定义关系区间与备注。
9
- - 初始好感度:可在自定义范围内随机生成,避免所有用户同值起步。
10
- - 安全守卫:当好感度低于自定义阈值时,记录到插件黑名单并全局拦截后续消息。
11
- - 双层好感度:短期情绪值负责即时反馈,长期关系值维护整体基调,互相制衡并支持半衰期、趋势动量调节。
12
- - 控制台名单:自动拉黑后会同步到配置表,方便复核与手动维护。
13
- - 自动分析:收到私聊、@、引用或命中 bot 昵称时,调用指定模型分析对话并调整好感度。
14
- - 调整工具:
15
- - `adjust_affinity` 将好感度设为指定数值,并同步关系区间。
16
- - `adjust_relationship` 将关系切换为自定义称谓,同时把好感度调至对应区间的下限。
17
- - `adjust_blacklist` 管理自动拉黑名单,可快速拉黑或解除指定用户。
18
- - 特殊关系:可为指定用户记录“初始好感度 + 自定义称谓”,工具操作会实时写回配置。
19
- - 短期拉黑:短期好感跌破阈值时,可自动临时屏蔽用户若干小时并附带一次性好感惩罚。
20
-
21
- ## 双层好感度概览
22
-
23
- - **短期好感(ShortTerm)**:代表最近互动的情绪波动。支持指数衰减(半衰期)、最小/最大回归幅度,确保情绪会逐步回归中性。
24
- - **长期好感(LongTerm)**:描述关系的稳定基调。可在短期持续高涨/低迷时触发上调或下调,并对短期波动进行缓冲。
25
- - **趋势动量(Momentum)**:记录近期增减的平均趋势,在满足阈值时会放大或抑制长期调节。
26
- - 通过 `decayConfig` / `crossInfluenceConfig` / `momentumConfig` 三组配置,即可调节半衰期、阈值、窗口长度、步长、回拉比例等关键参数,快速适配不同角色与人设节奏。
27
-
28
- ## 主要配置
29
-
30
- | 字段 | 说明 |
31
- | --- | --- |
32
- | `variableName` | 好感度变量名称,默认 `affinity` |
33
- | `min` / `max` | 好感度最小值 / 最大值 |
34
- | `initialRandomMin` / `initialRandomMax` | 初始好感度随机区间(含边界,默认 20~40,取整数) |
35
- | `maxIncreasePerMessage` | 单次允许增加的最大幅度(提示词变量 `{{maxIncreasePerMessage}}`) |
36
- | `maxDecreasePerMessage` | 单次允许减少的最大幅度(提示词变量 `{{maxDecreasePerMessage}}`) |
37
- | `decayConfig` | 短期衰减设置:`halfLifeMinutes` 半衰期(分钟)、`minReturnPerUpdate` / `maxReturnPerUpdate` 单次回归幅度 |
38
- | `crossInfluenceConfig` | 短期→长期联动:`promoteThreshold` / `demoteThreshold` 阈值、`evaluationWindow` 连续消息数、`longTermStep` 步长、`shortTermPullback` 回拉比例 |
39
- | `momentumConfig` | 趋势动量:`windowSize` 滑动窗口、`smoothing` 平滑系数、`maxInfluence` 对长期调节的最大附加值 |
40
- | `model` | 用于分析的 ChatLuna 模型 |
41
- | `analysisPrompt` | 主提示词模板,支持 `{{currentAffinity}}` 等占位符 |
42
- | `personaSource` | 可选人设预设来源(`none` / `chatluna` / `custom`) |
43
- | `personaChatlunaPreset` | 当来源为 `chatluna` 时注入的预设名称 |
44
- | `personaCustomPreset` | 当来源为 `custom` 时注入的自定义文本 |
45
- | `triggerNicknames` | 触发分析的 bot 昵称列表(默认含 ChatLuna 配置的昵称/@ 名) |
46
- | `useLastAffinity` | 开启后变量能立即返回上一次结果(无需等待分析完成) |
47
- | `historyMessageCount` | 提供给模型的历史消息条数(从数据库或 group-analysis 插件取得) |
48
- | `enableAutoBlacklist` | 启用后,好感度低于阈值会写入黑名单并阻断消息 |
49
- | `blacklistThreshold` | 自动拉黑触发值(小于该值即触发) |
50
- | `blacklistLogInterception` | 拦截消息时是否输出日志 |
51
- | `shortTermBlacklist` | 短期拉黑设置:`enabled` 开关;`threshold` 触发阈值;`durationHours` 持续时长;`penalty` 触发时额外扣减的好感 |
52
- | `autoBlacklist` | 自动拉黑记录列表(自动维护,可在控制台查看与编辑) |
53
- | `relationships` | 特殊关系配置:`userId`、`initialAffinity`、`relation`、`note` |
54
- | `relationshipAffinityLevels` | 区间 → 称谓映射,默认提供“陌生人/友好/亲近/挚友” |
55
- | `registerAffinityTool` / `registerRelationshipTool` / `registerBlacklistTool` | 是否注册对应 ChatLuna 工具 |
56
- | `enablePokeTool` / `pokeToolName` | 注册 OneBot “戳一戳” 工具(默认 `poke_user`,需要 OneBot/NapCat 支持) |
57
- | `enableSetSelfProfileTool` / `setSelfProfileToolName` | 注册 OneBot “修改自身账户信息” 工具(默认 `set_self_profile`,需要 OneBot/NapCat 支持) |
58
- | `rankDefaultLimit` | 指令默认展示的排行榜人数 |
59
- | `rankRenderAsImage` | 指令默认是否渲染排行榜为图片(图片模式需 `koishi-plugin-puppeteer`) |
60
- | `blacklistDefaultLimit` | `affinity.blacklist` 默认展示的黑名单条目数 |
61
- | `blacklistRenderAsImage` | 黑名单指令默认是否渲染为图片 |
62
- | `random` | 其他变量配置(启用开关 + 变量名称) |
63
- | `debugLogging` | 输出调试日志,便于观察模型解析与好感度计算细节 |
64
-
65
- ## 其他变量
66
-
67
- - `random`:随机选项或范围变量,支持列表、区间(`1-10`)或混合写法
68
- - 可配置 `enabled` 与 `variableName`
69
-
70
- ## 指令
71
-
72
- - `affinity.rank [limit] [platform] [image|text]`:查看好感度排行,可指定人数、平台,并选择文本或图片输出(图片模式需 `koishi-plugin-puppeteer`)。
73
- - `affinity.inspect [userId] [platform]`:查看指定用户的长期/短期好感、动量与衰减详情,方便调参与排查。
74
- - `affinity.blacklist [limit] [platform] [image|text]`:查看自动拉黑列表,支持筛选平台与图片输出。
75
- - `affinity.block <userId> [platform] [-n <note>]`:手动将用户加入自动黑名单,可附带备注。
76
- - `affinity.unblock <userId> [platform]`:解除自动黑名单。
77
-
78
- ## 工具调用
79
-
80
- 启用 `registerAffinityTool` 或 `registerRelationshipTool` 后,ChatLuna 代理可直接调用。
81
-
82
- - `enablePokeTool`:在 OneBot 平台注册 `poke_user` 工具,可在群聊或私聊中执行戳一戳。
83
- - `enableSetSelfProfileTool`:在 OneBot 平台注册 `set_self_profile` 工具,可修改机器人昵称/签名/性别(谨慎启用)。
84
-
85
- 若 `relation` 不在区间表中,会按全局初始值创建一条“自定义关系”条目,后续可在面板中继续编辑。
86
-
87
- ## 数据存储
88
-
89
- 插件会在数据库里创建表 `chatluna_affinity_records`,字段包含:
90
-
91
- - `platform` / `userId` / `selfId`
92
- - `affinityInited`(是否完成初始化)
93
- - `affinity`(综合值)、`shortTermAffinity`、`longTermAffinity`
94
- - `momentum`
95
- - `updatedAt`、`shortTermUpdatedAt`、`longTermUpdatedAt`、`momentumUpdatedAt`
96
- - `relation`、`relationUpdatedAt`
97
- - `nickname`
98
-
99
- 旧版本仅存储单一好感度的记录会在首次读取时自动拆分为 9:1 的长期 / 短期结构,无需额外迁移脚本。
100
-
101
- ## 调试
102
-
103
- 开启 `debugLogging` 后,控制台会输出:
104
-
105
- - 触发判定:昵称集合、@ 命中、引用命中
106
- - 模型返回的 `delta`、缓冲后 `bufferedDelta` 与衰减信息
107
- - 好感度更新时会额外输出短期/长期值、动量、阈值触发情况
108
- - 配合 `affinity.inspect` 指令,可快速对照数据库与实时衰减后的状态
109
-
110
- 方便快速定位触发条件和模型配置问题。
111
-
112
- ## 常见问题
113
-
114
- 1. **没有触发分析?**
115
- - 确认 `enableAnalysis` 为 `true`,且消息满足私聊 / @ / 引用 / 昵称命中任一条件。
116
- 2. **工具调用失败?**
117
- - 确认配置里开启了对应工具开关;日志会提示是否缺失用户 ID 或关系名称。
118
- 3. **如何清理数据?**
119
- - 直接删除数据库中 `chatluna_affinity_records` 数据,或指定用户重新初始化即可。
120
-
121
- ## 许可协议
122
-
123
- MIT License © 2024 chatluna-affinity contributors