@aalis/plugin-flow-control 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.
- package/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/config.d.ts +77 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +178 -0
- package/dist/config.js.map +1 -0
- package/dist/i18n.d.ts +4 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +18 -0
- package/dist/i18n.js.map +1 -0
- package/dist/idle-scheduler.d.ts +22 -0
- package/dist/idle-scheduler.d.ts.map +1 -0
- package/dist/idle-scheduler.js +174 -0
- package/dist/idle-scheduler.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +404 -0
- package/dist/index.js.map +1 -0
- package/dist/state.d.ts +34 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +72 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ace Nyan <ace@acenyan.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @aalis/plugin-flow-control
|
|
2
|
+
|
|
3
|
+
平台无关流控:禁言/冷却/限速/闲置触发
|
|
4
|
+
## 角色
|
|
5
|
+
|
|
6
|
+
运行时插件
|
|
7
|
+
|
|
8
|
+
## 安装
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pnpm add @aalis/plugin-flow-control
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 文档
|
|
15
|
+
|
|
16
|
+
详见 [docs/plugins/plugin-flow-control.md](../../docs/plugins/plugin-flow-control.md)。
|
|
17
|
+
|
|
18
|
+
## 许可
|
|
19
|
+
|
|
20
|
+
见仓库根目录 LICENSE。
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface FlowControlConfig {
|
|
2
|
+
/**
|
|
3
|
+
* 统一作用域名单(multiselect),元素格式 "platform:sessionType[:targetId]",
|
|
4
|
+
* 支持 "*" 通配:onebot:group / onebot:* / *:group / * / onebot:private:10001 。
|
|
5
|
+
* 默认 ['*:group'] 与历史 OneBot ChatFlow 行为一致。
|
|
6
|
+
* 空数组 = 不生效(等于禁用流控);但若存在任一 overrides[].scope 命中也视为启用。
|
|
7
|
+
*/
|
|
8
|
+
scopes: string[];
|
|
9
|
+
/**
|
|
10
|
+
* 分作用域覆盖:每条覆盖针对一个 scope 字符串(语法同 scopes,3 段),
|
|
11
|
+
* 仅在该 scope 命中时把列出的字段覆盖到顶层默认之上;未列字段穿透到顶层。
|
|
12
|
+
* 命中时按"最具体优先"挑选(targetId > sessionType > platform > 通配)。
|
|
13
|
+
* 写一条 override 即自动启用该 scope,无需重复在 scopes 中列出。
|
|
14
|
+
* 例:private 单独 10 秒冷却而群聊不变 →
|
|
15
|
+
* overrides: [{ scope: '*:private', cooldownSeconds: 10 }]
|
|
16
|
+
*/
|
|
17
|
+
overrides: ScopeOverride[];
|
|
18
|
+
/** 固定间隔:每 N 条消息累计一次触发 */
|
|
19
|
+
fixedInterval: number;
|
|
20
|
+
/** 动态阈值上下限(用于回复后高、长时间无回复后低) */
|
|
21
|
+
activityScoreLower: number;
|
|
22
|
+
activityScoreUpper: number;
|
|
23
|
+
/** 阈值衰减分钟数:上次回复到当前的时间差越大,阈值越低 */
|
|
24
|
+
activityDecayMinutes: number;
|
|
25
|
+
/** 评分本身的衰减分钟数(0 表示评分不主动衰减) */
|
|
26
|
+
scoreDecayMinutes: number;
|
|
27
|
+
/** 回复后冷却(秒) */
|
|
28
|
+
cooldownSeconds: number;
|
|
29
|
+
/** mute 关键词命中时的禁言时长(秒) */
|
|
30
|
+
muteTimeSeconds: number;
|
|
31
|
+
/** 限速窗口(秒,0 关闭) */
|
|
32
|
+
rateLimitWindow: number;
|
|
33
|
+
/** 窗口内最大回复次数 */
|
|
34
|
+
rateLimitMaxReplies: number;
|
|
35
|
+
/** 闲置触发范围 */
|
|
36
|
+
idleTriggerScope: 'off' | 'session' | 'platform';
|
|
37
|
+
idleTriggerStrategy: 'all-quiet' | 'fixed';
|
|
38
|
+
idleTriggerMinutes: number;
|
|
39
|
+
idleTriggerStyle: 'exponential' | 'fixed';
|
|
40
|
+
idleTriggerMaxMinutes: number;
|
|
41
|
+
idleTriggerJitter: boolean;
|
|
42
|
+
/** 闲置触发注入的 system 提示文本 */
|
|
43
|
+
idleTriggerPrompt: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 分作用域覆盖项:含 scope 字符串 + 任意字段覆盖。
|
|
47
|
+
* 未指定的字段会从顶层 FlowControlConfig 默认中穿透。
|
|
48
|
+
*/
|
|
49
|
+
export interface ScopeOverride {
|
|
50
|
+
scope: string;
|
|
51
|
+
fixedInterval?: number;
|
|
52
|
+
activityScoreLower?: number;
|
|
53
|
+
activityScoreUpper?: number;
|
|
54
|
+
activityDecayMinutes?: number;
|
|
55
|
+
scoreDecayMinutes?: number;
|
|
56
|
+
cooldownSeconds?: number;
|
|
57
|
+
muteTimeSeconds?: number;
|
|
58
|
+
rateLimitWindow?: number;
|
|
59
|
+
rateLimitMaxReplies?: number;
|
|
60
|
+
idleTriggerScope?: 'off' | 'session' | 'platform';
|
|
61
|
+
idleTriggerStrategy?: 'all-quiet' | 'fixed';
|
|
62
|
+
idleTriggerMinutes?: number;
|
|
63
|
+
idleTriggerStyle?: 'exponential' | 'fixed';
|
|
64
|
+
idleTriggerMaxMinutes?: number;
|
|
65
|
+
idleTriggerJitter?: boolean;
|
|
66
|
+
idleTriggerPrompt?: string;
|
|
67
|
+
}
|
|
68
|
+
export declare const defaultFlowControlConfig: FlowControlConfig;
|
|
69
|
+
export declare function resolveFlowControlConfig(raw: Record<string, unknown>): FlowControlConfig;
|
|
70
|
+
/** 统一作用域匹配:`(platform, sessionType[, targetId])` 是否命中 cfg.scopes 或任一 overrides[].scope。 */
|
|
71
|
+
export declare function isScopeEnabled(cfg: FlowControlConfig, platform: string | undefined, sessionType: string | undefined, targetId?: string | undefined): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* 在 cfg.overrides 中找出最具体匹配项,把其字段叠加到 base cfg 之上;无匹配时原样返回。
|
|
74
|
+
* 具体度:精确 targetId > 精确 sessionType > 精确 platform > 通配。
|
|
75
|
+
*/
|
|
76
|
+
export declare function resolveEffectiveConfig(cfg: FlowControlConfig, platform: string | undefined, sessionType: string | undefined, targetId?: string | undefined): FlowControlConfig;
|
|
77
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;;;;;;OAOG;IACH,SAAS,EAAE,aAAa,EAAE,CAAC;IAE3B,yBAAyB;IACzB,aAAa,EAAE,MAAM,CAAC;IAEtB,+BAA+B;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iCAAiC;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,8BAA8B;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAE1B,eAAe;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,eAAe,EAAE,MAAM,CAAC;IAExB,mBAAmB;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB;IAChB,mBAAmB,EAAE,MAAM,CAAC;IAE5B,aAAa;IACb,gBAAgB,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,CAAC;IACjD,mBAAmB,EAAE,WAAW,GAAG,OAAO,CAAC;IAC3C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,aAAa,GAAG,OAAO,CAAC;IAC1C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0BAA0B;IAC1B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,CAAC;IAClD,mBAAmB,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IAC3C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,wBAAwB,EAAE,iBAmBtC,CAAC;AAaF,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,CA4BxF;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,CAC5B,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAWT;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAC5B,iBAAiB,CAwBnB"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// ----- 流控配置类型与默认值 -----
|
|
2
|
+
export const defaultFlowControlConfig = {
|
|
3
|
+
scopes: ['*:group'],
|
|
4
|
+
overrides: [],
|
|
5
|
+
fixedInterval: 5,
|
|
6
|
+
activityScoreLower: 0.3,
|
|
7
|
+
activityScoreUpper: 0.85,
|
|
8
|
+
activityDecayMinutes: 10,
|
|
9
|
+
scoreDecayMinutes: 0,
|
|
10
|
+
cooldownSeconds: 10,
|
|
11
|
+
muteTimeSeconds: 60,
|
|
12
|
+
rateLimitWindow: 0,
|
|
13
|
+
rateLimitMaxReplies: 10,
|
|
14
|
+
idleTriggerScope: 'off',
|
|
15
|
+
idleTriggerStrategy: 'all-quiet',
|
|
16
|
+
idleTriggerMinutes: 180,
|
|
17
|
+
idleTriggerStyle: 'exponential',
|
|
18
|
+
idleTriggerMaxMinutes: 1440,
|
|
19
|
+
idleTriggerJitter: true,
|
|
20
|
+
idleTriggerPrompt: '',
|
|
21
|
+
};
|
|
22
|
+
function parseStringList(val) {
|
|
23
|
+
if (Array.isArray(val))
|
|
24
|
+
return val.filter(Boolean).map(String);
|
|
25
|
+
if (typeof val === 'string' && val.trim()) {
|
|
26
|
+
return val
|
|
27
|
+
.split(',')
|
|
28
|
+
.map(s => s.trim())
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
export function resolveFlowControlConfig(raw) {
|
|
34
|
+
const d = defaultFlowControlConfig;
|
|
35
|
+
return {
|
|
36
|
+
scopes: raw.scopes === undefined ? d.scopes : parseStringList(raw.scopes),
|
|
37
|
+
overrides: parseOverrides(raw.overrides),
|
|
38
|
+
fixedInterval: raw.fixedInterval ?? d.fixedInterval,
|
|
39
|
+
activityScoreLower: raw.activityScoreLower ?? d.activityScoreLower,
|
|
40
|
+
activityScoreUpper: raw.activityScoreUpper ?? d.activityScoreUpper,
|
|
41
|
+
activityDecayMinutes: raw.activityDecayMinutes ?? d.activityDecayMinutes,
|
|
42
|
+
scoreDecayMinutes: raw.scoreDecayMinutes ?? d.scoreDecayMinutes,
|
|
43
|
+
cooldownSeconds: raw.cooldownSeconds ?? d.cooldownSeconds,
|
|
44
|
+
muteTimeSeconds: raw.muteTimeSeconds ?? d.muteTimeSeconds,
|
|
45
|
+
rateLimitWindow: raw.rateLimitWindow ?? d.rateLimitWindow,
|
|
46
|
+
rateLimitMaxReplies: raw.rateLimitMaxReplies ?? d.rateLimitMaxReplies,
|
|
47
|
+
idleTriggerScope: (() => {
|
|
48
|
+
const v = raw.idleTriggerScope;
|
|
49
|
+
return v === 'off' || v === 'session' || v === 'platform' ? v : d.idleTriggerScope;
|
|
50
|
+
})(),
|
|
51
|
+
idleTriggerStrategy: (() => {
|
|
52
|
+
const v = raw.idleTriggerStrategy;
|
|
53
|
+
return v === 'fixed' ? 'fixed' : 'all-quiet';
|
|
54
|
+
})(),
|
|
55
|
+
idleTriggerMinutes: raw.idleTriggerMinutes ?? d.idleTriggerMinutes,
|
|
56
|
+
idleTriggerStyle: raw.idleTriggerStyle ?? d.idleTriggerStyle,
|
|
57
|
+
idleTriggerMaxMinutes: raw.idleTriggerMaxMinutes ?? d.idleTriggerMaxMinutes,
|
|
58
|
+
idleTriggerJitter: raw.idleTriggerJitter ?? d.idleTriggerJitter,
|
|
59
|
+
idleTriggerPrompt: raw.idleTriggerPrompt || d.idleTriggerPrompt,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** 统一作用域匹配:`(platform, sessionType[, targetId])` 是否命中 cfg.scopes 或任一 overrides[].scope。 */
|
|
63
|
+
export function isScopeEnabled(cfg, platform, sessionType, targetId) {
|
|
64
|
+
const p = platform ?? '';
|
|
65
|
+
const t = sessionType ?? '';
|
|
66
|
+
const tid = targetId ?? '';
|
|
67
|
+
for (const raw of cfg.scopes) {
|
|
68
|
+
if (matchScopeString(raw, p, t, tid))
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
for (const o of cfg.overrides) {
|
|
72
|
+
if (matchScopeString(o.scope, p, t, tid))
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 在 cfg.overrides 中找出最具体匹配项,把其字段叠加到 base cfg 之上;无匹配时原样返回。
|
|
79
|
+
* 具体度:精确 targetId > 精确 sessionType > 精确 platform > 通配。
|
|
80
|
+
*/
|
|
81
|
+
export function resolveEffectiveConfig(cfg, platform, sessionType, targetId) {
|
|
82
|
+
if (cfg.overrides.length === 0)
|
|
83
|
+
return cfg;
|
|
84
|
+
const p = platform ?? '';
|
|
85
|
+
const t = sessionType ?? '';
|
|
86
|
+
const tid = targetId ?? '';
|
|
87
|
+
let best = null;
|
|
88
|
+
let bestSpec = -1;
|
|
89
|
+
for (const o of cfg.overrides) {
|
|
90
|
+
const parts = parseScopePattern(o.scope);
|
|
91
|
+
if (!matchScopeParts(parts, p, t, tid))
|
|
92
|
+
continue;
|
|
93
|
+
const spec = scopeSpecificity(parts);
|
|
94
|
+
if (spec > bestSpec) {
|
|
95
|
+
best = o;
|
|
96
|
+
bestSpec = spec;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!best)
|
|
100
|
+
return cfg;
|
|
101
|
+
const merged = { ...cfg };
|
|
102
|
+
for (const [k, v] of Object.entries(best)) {
|
|
103
|
+
if (k === 'scope')
|
|
104
|
+
continue;
|
|
105
|
+
if (v === undefined)
|
|
106
|
+
continue;
|
|
107
|
+
merged[k] = v;
|
|
108
|
+
}
|
|
109
|
+
return merged;
|
|
110
|
+
}
|
|
111
|
+
function parseScopePattern(s) {
|
|
112
|
+
const parts = (s || '').split(':');
|
|
113
|
+
return {
|
|
114
|
+
platform: parts[0] || '*',
|
|
115
|
+
sessionType: parts[1] || '*',
|
|
116
|
+
targetId: parts[2] || '*',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function matchScopeParts(pat, p, t, tid) {
|
|
120
|
+
return ((pat.platform === '*' || pat.platform === '' || pat.platform === p) &&
|
|
121
|
+
(pat.sessionType === '*' || pat.sessionType === '' || pat.sessionType === t) &&
|
|
122
|
+
(pat.targetId === '*' || pat.targetId === '' || pat.targetId === tid));
|
|
123
|
+
}
|
|
124
|
+
function matchScopeString(raw, p, t, tid) {
|
|
125
|
+
return matchScopeParts(parseScopePattern(raw), p, t, tid);
|
|
126
|
+
}
|
|
127
|
+
function scopeSpecificity(pat) {
|
|
128
|
+
return ((pat.platform !== '*' && pat.platform !== '' ? 4 : 0) +
|
|
129
|
+
(pat.sessionType !== '*' && pat.sessionType !== '' ? 2 : 0) +
|
|
130
|
+
(pat.targetId !== '*' && pat.targetId !== '' ? 1 : 0));
|
|
131
|
+
}
|
|
132
|
+
function parseOverrides(raw) {
|
|
133
|
+
if (!Array.isArray(raw))
|
|
134
|
+
return [];
|
|
135
|
+
const out = [];
|
|
136
|
+
for (const item of raw) {
|
|
137
|
+
if (!item || typeof item !== 'object')
|
|
138
|
+
continue;
|
|
139
|
+
const obj = item;
|
|
140
|
+
if (typeof obj.scope !== 'string' || !obj.scope.trim())
|
|
141
|
+
continue;
|
|
142
|
+
const o = { scope: obj.scope.trim() };
|
|
143
|
+
for (const k of [
|
|
144
|
+
'fixedInterval',
|
|
145
|
+
'activityScoreLower',
|
|
146
|
+
'activityScoreUpper',
|
|
147
|
+
'activityDecayMinutes',
|
|
148
|
+
'scoreDecayMinutes',
|
|
149
|
+
'cooldownSeconds',
|
|
150
|
+
'muteTimeSeconds',
|
|
151
|
+
'rateLimitWindow',
|
|
152
|
+
'rateLimitMaxReplies',
|
|
153
|
+
'idleTriggerMinutes',
|
|
154
|
+
'idleTriggerMaxMinutes',
|
|
155
|
+
]) {
|
|
156
|
+
if (typeof obj[k] === 'number')
|
|
157
|
+
o[k] = obj[k];
|
|
158
|
+
}
|
|
159
|
+
if (typeof obj.idleTriggerJitter === 'boolean')
|
|
160
|
+
o.idleTriggerJitter = obj.idleTriggerJitter;
|
|
161
|
+
// 字符串字段:仅在非空时视为覆盖;空串/未填 → 穿透到顶层默认
|
|
162
|
+
if (typeof obj.idleTriggerPrompt === 'string' && obj.idleTriggerPrompt !== '') {
|
|
163
|
+
o.idleTriggerPrompt = obj.idleTriggerPrompt;
|
|
164
|
+
}
|
|
165
|
+
const sScope = obj.idleTriggerScope;
|
|
166
|
+
if (sScope === 'off' || sScope === 'session' || sScope === 'platform')
|
|
167
|
+
o.idleTriggerScope = sScope;
|
|
168
|
+
const sStrat = obj.idleTriggerStrategy;
|
|
169
|
+
if (sStrat === 'all-quiet' || sStrat === 'fixed')
|
|
170
|
+
o.idleTriggerStrategy = sStrat;
|
|
171
|
+
const sStyle = obj.idleTriggerStyle;
|
|
172
|
+
if (sStyle === 'exponential' || sStyle === 'fixed')
|
|
173
|
+
o.idleTriggerStyle = sStyle;
|
|
174
|
+
out.push(o);
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,yBAAyB;AA6EzB,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,MAAM,EAAE,CAAC,SAAS,CAAC;IACnB,SAAS,EAAE,EAAE;IACb,aAAa,EAAE,CAAC;IAChB,kBAAkB,EAAE,GAAG;IACvB,kBAAkB,EAAE,IAAI;IACxB,oBAAoB,EAAE,EAAE;IACxB,iBAAiB,EAAE,CAAC;IACpB,eAAe,EAAE,EAAE;IACnB,eAAe,EAAE,EAAE;IACnB,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,EAAE;IACvB,gBAAgB,EAAE,KAAK;IACvB,mBAAmB,EAAE,WAAW;IAChC,kBAAkB,EAAE,GAAG;IACvB,gBAAgB,EAAE,aAAa;IAC/B,qBAAqB,EAAE,IAAI;IAC3B,iBAAiB,EAAE,IAAI;IACvB,iBAAiB,EAAE,EAAE;CACtB,CAAC;AAEF,SAAS,eAAe,CAAC,GAAY;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/D,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1C,OAAO,GAAG;aACP,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAClB,MAAM,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,GAA4B;IACnE,MAAM,CAAC,GAAG,wBAAwB,CAAC;IACnC,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC;QACzE,SAAS,EAAE,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;QACxC,aAAa,EAAG,GAAG,CAAC,aAAwB,IAAI,CAAC,CAAC,aAAa;QAC/D,kBAAkB,EAAG,GAAG,CAAC,kBAA6B,IAAI,CAAC,CAAC,kBAAkB;QAC9E,kBAAkB,EAAG,GAAG,CAAC,kBAA6B,IAAI,CAAC,CAAC,kBAAkB;QAC9E,oBAAoB,EAAG,GAAG,CAAC,oBAA+B,IAAI,CAAC,CAAC,oBAAoB;QACpF,iBAAiB,EAAG,GAAG,CAAC,iBAA4B,IAAI,CAAC,CAAC,iBAAiB;QAC3E,eAAe,EAAG,GAAG,CAAC,eAA0B,IAAI,CAAC,CAAC,eAAe;QACrE,eAAe,EAAG,GAAG,CAAC,eAA0B,IAAI,CAAC,CAAC,eAAe;QACrE,eAAe,EAAG,GAAG,CAAC,eAA0B,IAAI,CAAC,CAAC,eAAe;QACrE,mBAAmB,EAAG,GAAG,CAAC,mBAA8B,IAAI,CAAC,CAAC,mBAAmB;QACjF,gBAAgB,EAAE,CAAC,GAA0C,EAAE;YAC7D,MAAM,CAAC,GAAG,GAAG,CAAC,gBAAgB,CAAC;YAC/B,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC;QACrF,CAAC,CAAC,EAAE;QACJ,mBAAmB,EAAE,CAAC,GAA6C,EAAE;YACnE,MAAM,CAAC,GAAG,GAAG,CAAC,mBAAmB,CAAC;YAClC,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;QAC/C,CAAC,CAAC,EAAE;QACJ,kBAAkB,EAAG,GAAG,CAAC,kBAA6B,IAAI,CAAC,CAAC,kBAAkB;QAC9E,gBAAgB,EAAG,GAAG,CAAC,gBAA0D,IAAI,CAAC,CAAC,gBAAgB;QACvG,qBAAqB,EAAG,GAAG,CAAC,qBAAgC,IAAI,CAAC,CAAC,qBAAqB;QACvF,iBAAiB,EAAG,GAAG,CAAC,iBAA6B,IAAI,CAAC,CAAC,iBAAiB;QAC5E,iBAAiB,EAAG,GAAG,CAAC,iBAA4B,IAAI,CAAC,CAAC,iBAAiB;KAC5E,CAAC;AACJ,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,cAAc,CAC5B,GAAsB,EACtB,QAA4B,EAC5B,WAA+B,EAC/B,QAA6B;IAE7B,MAAM,CAAC,GAAG,QAAQ,IAAI,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,WAAW,IAAI,EAAE,CAAC;IAC5B,MAAM,GAAG,GAAG,QAAQ,IAAI,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,gBAAgB,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;IACpD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAC9B,IAAI,gBAAgB,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAsB,EACtB,QAA4B,EAC5B,WAA+B,EAC/B,QAA6B;IAE7B,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC3C,MAAM,CAAC,GAAG,QAAQ,IAAI,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,WAAW,IAAI,EAAE,CAAC;IAC5B,MAAM,GAAG,GAAG,QAAQ,IAAI,EAAE,CAAC;IAC3B,IAAI,IAAI,GAAyB,IAAI,CAAC;IACtC,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;IAClB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;YAAE,SAAS;QACjD,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;YACpB,IAAI,GAAG,CAAC,CAAC;YACT,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,CAAC;IACtB,MAAM,MAAM,GAAsB,EAAE,GAAG,GAAG,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,OAAO;YAAE,SAAS;QAC5B,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC7B,MAA6C,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAQD,SAAS,iBAAiB,CAAC,CAAS;IAClC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG;QACzB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG;QAC5B,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAiB,EAAE,CAAS,EAAE,CAAS,EAAE,GAAW;IAC3E,OAAO,CACL,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC;QACnE,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,IAAI,GAAG,CAAC,WAAW,KAAK,EAAE,IAAI,GAAG,CAAC,WAAW,KAAK,CAAC,CAAC;QAC5E,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,CACtE,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW,EAAE,CAAS,EAAE,CAAS,EAAE,GAAW;IACtE,OAAO,eAAe,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAiB;IACzC,OAAO,CACL,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,IAAI,GAAG,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACtD,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QAChD,MAAM,GAAG,GAAG,IAA+B,CAAC;QAC5C,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;YAAE,SAAS;QACjE,MAAM,CAAC,GAAkB,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI;YACd,eAAe;YACf,oBAAoB;YACpB,oBAAoB;YACpB,sBAAsB;YACtB,mBAAmB;YACnB,iBAAiB;YACjB,iBAAiB;YACjB,iBAAiB;YACjB,qBAAqB;YACrB,oBAAoB;YACpB,uBAAuB;SACf,EAAE,CAAC;YACX,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,QAAQ;gBAAG,CAAwC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACxF,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,iBAAiB,KAAK,SAAS;YAAE,CAAC,CAAC,iBAAiB,GAAG,GAAG,CAAC,iBAAiB,CAAC;QAC5F,kCAAkC;QAClC,IAAI,OAAO,GAAG,CAAC,iBAAiB,KAAK,QAAQ,IAAI,GAAG,CAAC,iBAAiB,KAAK,EAAE,EAAE,CAAC;YAC9E,CAAC,CAAC,iBAAiB,GAAG,GAAG,CAAC,iBAAiB,CAAC;QAC9C,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC;QACpC,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,UAAU;YAAE,CAAC,CAAC,gBAAgB,GAAG,MAAM,CAAC;QACnG,MAAM,MAAM,GAAG,GAAG,CAAC,mBAAmB,CAAC;QACvC,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,OAAO;YAAE,CAAC,CAAC,mBAAmB,GAAG,MAAM,CAAC;QACjF,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC;QACpC,IAAI,MAAM,KAAK,aAAa,IAAI,MAAM,KAAK,OAAO;YAAE,CAAC,CAAC,gBAAgB,GAAG,MAAM,CAAC;QAChF,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { I18nResources } from '@aalis/core';
|
|
2
|
+
export declare const DEFAULT_IDLE_PROMPT_ZH = "\u5F53\u524D\u4F1A\u8BDD\u5DF2\u957F\u65F6\u95F4\u65E0\u6D88\u606F\uFF0C\u8BF7\u6839\u636E\u4EBA\u8BBE\u4E3B\u52A8\u5F00\u542F\u4E00\u4E2A\u8F7B\u677E\u7684\u8BDD\u9898\u6216\u95EE\u5019\u3002\u4E0D\u8981\u63D0\u53CA\"\u7CFB\u7EDF\u63D0\u793A\"\u6216\u8868\u660E\u4F60\u662F\u88AB\u89E6\u53D1\u53D1\u8A00\u7684\u3002";
|
|
3
|
+
export declare const i18n: I18nResources;
|
|
4
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,eAAO,MAAM,sBAAsB,iUAA2D,CAAC;AAE/F,eAAO,MAAM,IAAI,EAAE,aAelB,CAAC"}
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const DEFAULT_IDLE_PROMPT_ZH = '当前会话已长时间无消息,请根据人设主动开启一个轻松的话题或问候。不要提及"系统提示"或表明你是被触发发言的。';
|
|
2
|
+
export const i18n = {
|
|
3
|
+
'zh-CN': {
|
|
4
|
+
'plugin.flowControl.displayName': '消息流控',
|
|
5
|
+
'config.flowControl.promptLocale.label': 'Prompt 语言',
|
|
6
|
+
'config.flowControl.promptLocale.description': '默认闲置触发提示词使用的语言。自定义闲置触发提示词不受此项影响。',
|
|
7
|
+
'config.flowControl.promptLocale.auto': '跟随全局设置',
|
|
8
|
+
'prompt.flowControl.idle': DEFAULT_IDLE_PROMPT_ZH,
|
|
9
|
+
},
|
|
10
|
+
'en-US': {
|
|
11
|
+
'plugin.flowControl.displayName': 'Flow Control',
|
|
12
|
+
'config.flowControl.promptLocale.label': 'Prompt Language',
|
|
13
|
+
'config.flowControl.promptLocale.description': 'Language used by the default idle-trigger prompt. Custom idle-trigger prompts are left unchanged.',
|
|
14
|
+
'config.flowControl.promptLocale.auto': 'Follow Global Setting',
|
|
15
|
+
'prompt.flowControl.idle': 'This conversation has been idle for a long time. Based on the persona, proactively start a light topic or greeting. Do not mention a "system prompt" or reveal that this message was triggered automatically.',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,sBAAsB,GAAG,wDAAwD,CAAC;AAE/F,MAAM,CAAC,MAAM,IAAI,GAAkB;IACjC,OAAO,EAAE;QACP,gCAAgC,EAAE,MAAM;QACxC,uCAAuC,EAAE,WAAW;QACpD,6CAA6C,EAAE,kCAAkC;QACjF,sCAAsC,EAAE,QAAQ;QAChD,yBAAyB,EAAE,sBAAsB;KAClD;IACD,OAAO,EAAE;QACP,gCAAgC,EAAE,cAAc;QAChD,uCAAuC,EAAE,iBAAiB;QAC1D,6CAA6C,EAAE,mGAAmG;QAClJ,sCAAsC,EAAE,uBAAuB;QAC/D,yBAAyB,EAAE,+MAA+M;KAC3O;CACF,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Context } from '@aalis/core';
|
|
2
|
+
import { type FlowControlConfig } from './config.js';
|
|
3
|
+
import type { MutableFlowSessionState } from './state.js';
|
|
4
|
+
export declare function scheduleSessionIdle(ctx: Context, cfg: FlowControlConfig, state: MutableFlowSessionState, sessionId: string, platform: string, reschedule: () => void): void;
|
|
5
|
+
export declare function clearSessionIdle(state: MutableFlowSessionState): void;
|
|
6
|
+
export declare class PlatformIdleScheduler {
|
|
7
|
+
private readonly ctx;
|
|
8
|
+
private readonly cfg;
|
|
9
|
+
private readonly states;
|
|
10
|
+
private timer;
|
|
11
|
+
private running;
|
|
12
|
+
constructor(ctx: Context, cfg: FlowControlConfig, states: Map<string, MutableFlowSessionState>);
|
|
13
|
+
start(): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
/** 距离全部会话静默达标还需多少 ms(返回 0 = 已达标 / 无活跃会话) */
|
|
16
|
+
private timeUntilAllQuiet;
|
|
17
|
+
/** 选一个最适合主动开聊的 sessionId */
|
|
18
|
+
private pickTarget;
|
|
19
|
+
private runOnce;
|
|
20
|
+
private schedule;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=idle-scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-scheduler.d.ts","sourceRoot":"","sources":["../src/idle-scheduler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,KAAK,iBAAiB,EAA0B,MAAM,aAAa,CAAC;AAC7E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AA0B1D,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,uBAAuB,EAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,IAAI,GACrB,IAAI,CA8BN;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAKrE;AAID,qBAAa,qBAAqB;IAK9B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,KAAK,CAA8C;IAC3D,OAAO,CAAC,OAAO,CAAS;gBAGL,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC;IAG/D,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI;IAOZ,4CAA4C;IAC5C,OAAO,CAAC,iBAAiB;IAWzB,4BAA4B;IAC5B,OAAO,CAAC,UAAU;YAoBJ,OAAO;IAqBrB,OAAO,CAAC,QAAQ;CA6BjB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// ----- 闲置触发调度器 -----
|
|
2
|
+
//
|
|
3
|
+
// session 范围:每会话一个 setTimeout,触发时合成 system 提示注入 gateway。
|
|
4
|
+
// platform 范围:跨平台一个 tick,挑"最久未联系"的 session 主动开聊。
|
|
5
|
+
import { resolveEffectiveConfig } from './config.js';
|
|
6
|
+
const DEFAULT_PROMPT = '当前会话已长时间无消息,请根据人设主动开启一个轻松的话题或问候。不要提及"系统提示"或表明你是被触发发言的。';
|
|
7
|
+
function buildIdleMessage(sessionId, platform, prompt) {
|
|
8
|
+
return {
|
|
9
|
+
content: prompt?.trim() ? prompt : DEFAULT_PROMPT,
|
|
10
|
+
sessionId,
|
|
11
|
+
platform,
|
|
12
|
+
source: 'idle-trigger',
|
|
13
|
+
triggerType: 'idle',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function injectIdle(ctx, msg) {
|
|
17
|
+
const gateway = ctx.getService('gateway');
|
|
18
|
+
if (gateway) {
|
|
19
|
+
await gateway.ingressMessage(msg);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
await ctx.emit('inbound:message', msg);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// ===== session 范围调度 =====
|
|
26
|
+
export function scheduleSessionIdle(ctx, cfg, state, sessionId, platform, reschedule) {
|
|
27
|
+
clearSessionIdle(state);
|
|
28
|
+
if (cfg.idleTriggerScope !== 'session')
|
|
29
|
+
return;
|
|
30
|
+
if (cfg.idleTriggerMinutes <= 0)
|
|
31
|
+
return;
|
|
32
|
+
let delayMs;
|
|
33
|
+
if (cfg.idleTriggerStyle === 'exponential') {
|
|
34
|
+
delayMs = Math.min(cfg.idleTriggerMinutes * state.idleBackoff * 60 * 1000, cfg.idleTriggerMaxMinutes * 60 * 1000);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
delayMs = cfg.idleTriggerMinutes * 60 * 1000;
|
|
38
|
+
}
|
|
39
|
+
if (cfg.idleTriggerJitter) {
|
|
40
|
+
const jitter = delayMs * (0.1 * (Math.random() * 2 - 1));
|
|
41
|
+
delayMs = Math.max(60_000, delayMs + jitter);
|
|
42
|
+
}
|
|
43
|
+
state.idleTimer = setTimeout(async () => {
|
|
44
|
+
try {
|
|
45
|
+
ctx.logger.info(`[flow] 空闲触发: session=${sessionId} (退避 x${state.idleBackoff})`);
|
|
46
|
+
if (cfg.idleTriggerStyle === 'exponential') {
|
|
47
|
+
state.idleBackoff = Math.min(state.idleBackoff * 2, 64);
|
|
48
|
+
}
|
|
49
|
+
await injectIdle(ctx, buildIdleMessage(sessionId, platform, cfg.idleTriggerPrompt));
|
|
50
|
+
reschedule();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
ctx.logger.warn(`空闲触发执行失败: ${err}`);
|
|
54
|
+
}
|
|
55
|
+
}, delayMs);
|
|
56
|
+
ctx.logger.debug(`[flow] 空闲触发已调度: session=${sessionId}, ${Math.round(delayMs / 60_000)}分钟后`);
|
|
57
|
+
}
|
|
58
|
+
export function clearSessionIdle(state) {
|
|
59
|
+
if (state.idleTimer) {
|
|
60
|
+
clearTimeout(state.idleTimer);
|
|
61
|
+
state.idleTimer = null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ===== platform 范围调度 =====
|
|
65
|
+
export class PlatformIdleScheduler {
|
|
66
|
+
ctx;
|
|
67
|
+
cfg;
|
|
68
|
+
states;
|
|
69
|
+
timer = null;
|
|
70
|
+
running = false;
|
|
71
|
+
constructor(ctx, cfg, states) {
|
|
72
|
+
this.ctx = ctx;
|
|
73
|
+
this.cfg = cfg;
|
|
74
|
+
this.states = states;
|
|
75
|
+
}
|
|
76
|
+
start() {
|
|
77
|
+
this.schedule();
|
|
78
|
+
}
|
|
79
|
+
stop() {
|
|
80
|
+
if (this.timer) {
|
|
81
|
+
clearTimeout(this.timer);
|
|
82
|
+
this.timer = null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** 距离全部会话静默达标还需多少 ms(返回 0 = 已达标 / 无活跃会话) */
|
|
86
|
+
timeUntilAllQuiet(thresholdMs) {
|
|
87
|
+
let maxLast = 0;
|
|
88
|
+
for (const s of this.states.values()) {
|
|
89
|
+
const last = Math.max(s.lastMessageTime, s.lastReplyTime);
|
|
90
|
+
if (last > maxLast)
|
|
91
|
+
maxLast = last;
|
|
92
|
+
}
|
|
93
|
+
if (maxLast === 0)
|
|
94
|
+
return 0;
|
|
95
|
+
const elapsed = Date.now() - maxLast;
|
|
96
|
+
return Math.max(0, thresholdMs - elapsed);
|
|
97
|
+
}
|
|
98
|
+
/** 选一个最适合主动开聊的 sessionId */
|
|
99
|
+
pickTarget() {
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
let best = null;
|
|
102
|
+
for (const [sid, s] of this.states) {
|
|
103
|
+
if (s.mutedUntil > now)
|
|
104
|
+
continue;
|
|
105
|
+
if (s.cooldownUntil > now)
|
|
106
|
+
continue;
|
|
107
|
+
const e = resolveEffectiveConfig(this.cfg, s.platform, s.sessionType, s.targetId);
|
|
108
|
+
if (e.rateLimitWindow > 0 && e.rateLimitMaxReplies > 0) {
|
|
109
|
+
const windowStart = now - e.rateLimitWindow * 1000;
|
|
110
|
+
const used = s.replyTimestamps.filter(t => t > windowStart).length;
|
|
111
|
+
if (used >= e.rateLimitMaxReplies)
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const lastActivity = Math.max(s.lastMessageTime, s.lastReplyTime);
|
|
115
|
+
if (!best || lastActivity < best.lastActivity) {
|
|
116
|
+
best = { sessionId: sid, lastActivity, platform: s.platform };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return best;
|
|
120
|
+
}
|
|
121
|
+
async runOnce() {
|
|
122
|
+
if (this.running)
|
|
123
|
+
return;
|
|
124
|
+
this.running = true;
|
|
125
|
+
try {
|
|
126
|
+
const target = this.pickTarget();
|
|
127
|
+
if (!target) {
|
|
128
|
+
this.ctx.logger.debug('[flow] platform idle tick: 无可发送候选,跳过');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.ctx.logger.info(`[flow] platform idle tick: 主动开聊 → ${target.sessionId} ` +
|
|
132
|
+
`(idle=${Math.round((Date.now() - target.lastActivity) / 60_000)}min)`);
|
|
133
|
+
await injectIdle(this.ctx, buildIdleMessage(target.sessionId, target.platform, this.cfg.idleTriggerPrompt));
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
this.ctx.logger.warn(`[flow] platform idle tick 失败: ${err}`);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
this.running = false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
schedule() {
|
|
143
|
+
if (this.timer) {
|
|
144
|
+
clearTimeout(this.timer);
|
|
145
|
+
this.timer = null;
|
|
146
|
+
}
|
|
147
|
+
if (this.cfg.idleTriggerScope !== 'platform')
|
|
148
|
+
return;
|
|
149
|
+
if (this.cfg.idleTriggerMinutes <= 0)
|
|
150
|
+
return;
|
|
151
|
+
const baseMs = this.cfg.idleTriggerMinutes * 60_000;
|
|
152
|
+
let delay;
|
|
153
|
+
if (this.cfg.idleTriggerStrategy === 'fixed') {
|
|
154
|
+
delay = baseMs;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
delay = this.timeUntilAllQuiet(baseMs);
|
|
158
|
+
if (delay === 0)
|
|
159
|
+
delay = 1000;
|
|
160
|
+
}
|
|
161
|
+
this.timer = setTimeout(async () => {
|
|
162
|
+
if (this.cfg.idleTriggerStrategy === 'all-quiet') {
|
|
163
|
+
const remaining = this.timeUntilAllQuiet(baseMs);
|
|
164
|
+
if (remaining > 0) {
|
|
165
|
+
this.schedule();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
await this.runOnce();
|
|
170
|
+
this.schedule();
|
|
171
|
+
}, delay);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=idle-scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-scheduler.js","sourceRoot":"","sources":["../src/idle-scheduler.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConfigSchema, Context } from '@aalis/core';
|
|
2
|
+
import '@aalis/plugin-gateway-api';
|
|
3
|
+
export type { FlowControlService, FlowSessionStateSnapshot } from './types.js';
|
|
4
|
+
import { type FlowControlConfig } from './config.js';
|
|
5
|
+
export declare const name = "@aalis/plugin-flow-control";
|
|
6
|
+
export declare const displayName = "\u6D88\u606F\u6D41\u63A7";
|
|
7
|
+
export declare const subsystem = "core";
|
|
8
|
+
export declare const provides: string[];
|
|
9
|
+
export declare const inject: {
|
|
10
|
+
required: string[];
|
|
11
|
+
optional: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare const configSchema: ConfigSchema;
|
|
14
|
+
export declare const defaultConfig: FlowControlConfig;
|
|
15
|
+
export declare function apply(ctx: Context, raw: Record<string, unknown>): Promise<void>;
|
|
16
|
+
export type { FlowControlConfig };
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAOzD,OAAO,2BAA2B,CAAC;AAEnC,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,EAEL,KAAK,iBAAiB,EAIvB,MAAM,aAAa,CAAC;AAcrB,eAAO,MAAM,IAAI,+BAA+B,CAAC;AACjD,eAAO,MAAM,WAAW,6BAAS,CAAC;AAClC,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC,eAAO,MAAM,QAAQ,UAAmB,CAAC;AACzC,eAAO,MAAM,MAAM;;;CAGlB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,YA4G1B,CAAC;AAEF,eAAO,MAAM,aAAa,mBAA2B,CAAC;AAItD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAkRrF;AAGD,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { INBOUND_PHASE } from '@aalis/plugin-gateway-api';
|
|
2
|
+
import { createStorageGateway } from '@aalis/plugin-storage-api';
|
|
3
|
+
import '@aalis/plugin-gateway-api';
|
|
4
|
+
import { defaultFlowControlConfig, isScopeEnabled, resolveEffectiveConfig, resolveFlowControlConfig, } from './config.js';
|
|
5
|
+
import { clearSessionIdle, PlatformIdleScheduler, scheduleSessionIdle } from './idle-scheduler.js';
|
|
6
|
+
import { applyScoreDecay, calculateScoreIncrement, createState, getCurrentThreshold, rateLimitUsedNow, snapshot, } from './state.js';
|
|
7
|
+
// ----- 元数据 -----
|
|
8
|
+
export const name = '@aalis/plugin-flow-control';
|
|
9
|
+
export const displayName = '消息流控';
|
|
10
|
+
export const subsystem = 'core';
|
|
11
|
+
export const provides = ['flow-control'];
|
|
12
|
+
export const inject = {
|
|
13
|
+
required: ['gateway'],
|
|
14
|
+
optional: ['message-archive'],
|
|
15
|
+
};
|
|
16
|
+
export const configSchema = {
|
|
17
|
+
scopes: {
|
|
18
|
+
type: 'multiselect',
|
|
19
|
+
label: '生效作用域',
|
|
20
|
+
default: defaultFlowControlConfig.scopes,
|
|
21
|
+
dynamicOptions: 'gateway-scopes',
|
|
22
|
+
allowCustom: true,
|
|
23
|
+
description: '格式 platform:sessionType,支持通配 *;onebot:group / onebot:* / *:group / *。默认 *:group 与历史 OneBot 行为一致。',
|
|
24
|
+
},
|
|
25
|
+
fixedInterval: { type: 'number', label: '固定间隔(每 N 条触发)', default: defaultFlowControlConfig.fixedInterval },
|
|
26
|
+
activityScoreLower: { type: 'number', label: '活跃指数下限', default: defaultFlowControlConfig.activityScoreLower },
|
|
27
|
+
activityScoreUpper: { type: 'number', label: '活跃指数上限', default: defaultFlowControlConfig.activityScoreUpper },
|
|
28
|
+
activityDecayMinutes: {
|
|
29
|
+
type: 'number',
|
|
30
|
+
label: '阈值衰减分钟',
|
|
31
|
+
default: defaultFlowControlConfig.activityDecayMinutes,
|
|
32
|
+
},
|
|
33
|
+
scoreDecayMinutes: {
|
|
34
|
+
type: 'number',
|
|
35
|
+
label: '评分衰减分钟(0=不衰减)',
|
|
36
|
+
default: defaultFlowControlConfig.scoreDecayMinutes,
|
|
37
|
+
},
|
|
38
|
+
cooldownSeconds: { type: 'number', label: '回复后冷却(秒)', default: defaultFlowControlConfig.cooldownSeconds },
|
|
39
|
+
muteTimeSeconds: { type: 'number', label: '禁言关键词时长(秒)', default: defaultFlowControlConfig.muteTimeSeconds },
|
|
40
|
+
rateLimitWindow: {
|
|
41
|
+
type: 'number',
|
|
42
|
+
label: '限速窗口(秒,0=关闭)',
|
|
43
|
+
default: defaultFlowControlConfig.rateLimitWindow,
|
|
44
|
+
},
|
|
45
|
+
rateLimitMaxReplies: {
|
|
46
|
+
type: 'number',
|
|
47
|
+
label: '窗口内最大回复数',
|
|
48
|
+
default: defaultFlowControlConfig.rateLimitMaxReplies,
|
|
49
|
+
},
|
|
50
|
+
idleTriggerScope: {
|
|
51
|
+
type: 'select',
|
|
52
|
+
label: '闲置触发范围',
|
|
53
|
+
default: defaultFlowControlConfig.idleTriggerScope,
|
|
54
|
+
options: [
|
|
55
|
+
{ label: 'off (关闭)', value: 'off' },
|
|
56
|
+
{ label: 'session (每会话独立定时)', value: 'session' },
|
|
57
|
+
{ label: 'platform (跨会话选举)', value: 'platform' },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
idleTriggerStrategy: {
|
|
61
|
+
type: 'select',
|
|
62
|
+
label: '闲置触发策略',
|
|
63
|
+
default: defaultFlowControlConfig.idleTriggerStrategy,
|
|
64
|
+
options: [
|
|
65
|
+
{ label: 'all-quiet (所有会话都静默时)', value: 'all-quiet' },
|
|
66
|
+
{ label: 'fixed (固定间隔)', value: 'fixed' },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
idleTriggerMinutes: { type: 'number', label: '闲置触发分钟', default: defaultFlowControlConfig.idleTriggerMinutes },
|
|
70
|
+
idleTriggerStyle: {
|
|
71
|
+
type: 'select',
|
|
72
|
+
label: '闲置触发风格',
|
|
73
|
+
default: defaultFlowControlConfig.idleTriggerStyle,
|
|
74
|
+
options: [
|
|
75
|
+
{ label: 'exponential (指数退避)', value: 'exponential' },
|
|
76
|
+
{ label: 'fixed (固定)', value: 'fixed' },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
idleTriggerMaxMinutes: {
|
|
80
|
+
type: 'number',
|
|
81
|
+
label: '闲置触发上限分钟',
|
|
82
|
+
default: defaultFlowControlConfig.idleTriggerMaxMinutes,
|
|
83
|
+
},
|
|
84
|
+
idleTriggerJitter: { type: 'boolean', label: '闲置触发抖动', default: defaultFlowControlConfig.idleTriggerJitter },
|
|
85
|
+
idleTriggerPrompt: { type: 'string', label: '闲置触发系统提示', default: defaultFlowControlConfig.idleTriggerPrompt },
|
|
86
|
+
overrides: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
label: '分作用域覆盖',
|
|
89
|
+
description: '每项 {scope: "platform:sessionType[:targetId]", ...} 仅在该 scope 命中时覆盖列出的字段;字段留空(或不填)= 沿用上方默认,不会被覆盖为 0/空。最具体匹配优先(targetId > sessionType > platform > 通配)。例:scope="*:private", cooldownSeconds=10 让所有平台私聊单独 10s 冷却,其他字段继续走默认。',
|
|
90
|
+
default: [],
|
|
91
|
+
items: {
|
|
92
|
+
scope: {
|
|
93
|
+
type: 'string',
|
|
94
|
+
label: '作用域',
|
|
95
|
+
description: '格式 platform:sessionType[:targetId],支持 *',
|
|
96
|
+
required: true,
|
|
97
|
+
},
|
|
98
|
+
fixedInterval: { type: 'number', label: '固定间隔(每 N 条触发)' },
|
|
99
|
+
activityScoreLower: { type: 'number', label: '活跃指数下限' },
|
|
100
|
+
activityScoreUpper: { type: 'number', label: '活跃指数上限' },
|
|
101
|
+
activityDecayMinutes: { type: 'number', label: '阈值衰减分钟' },
|
|
102
|
+
scoreDecayMinutes: { type: 'number', label: '评分衰减分钟' },
|
|
103
|
+
cooldownSeconds: { type: 'number', label: '回复后冷却(秒)' },
|
|
104
|
+
muteTimeSeconds: { type: 'number', label: '禁言关键词时长(秒)' },
|
|
105
|
+
rateLimitWindow: { type: 'number', label: '限速窗口(秒)' },
|
|
106
|
+
rateLimitMaxReplies: { type: 'number', label: '窗口内最大回复数' },
|
|
107
|
+
idleTriggerScope: {
|
|
108
|
+
type: 'select',
|
|
109
|
+
label: '闲置触发范围',
|
|
110
|
+
options: [
|
|
111
|
+
{ label: 'off', value: 'off' },
|
|
112
|
+
{ label: 'session', value: 'session' },
|
|
113
|
+
{ label: 'platform', value: 'platform' },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
idleTriggerMinutes: { type: 'number', label: '闲置触发分钟' },
|
|
117
|
+
idleTriggerMaxMinutes: { type: 'number', label: '闲置触发上限分钟' },
|
|
118
|
+
idleTriggerJitter: { type: 'boolean', label: '闲置触发抖动' },
|
|
119
|
+
idleTriggerPrompt: { type: 'string', label: '闲置触发系统提示' },
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
export const defaultConfig = defaultFlowControlConfig;
|
|
124
|
+
// ----- 入口 -----
|
|
125
|
+
export async function apply(ctx, raw) {
|
|
126
|
+
const cfg = resolveFlowControlConfig(raw);
|
|
127
|
+
const states = new Map();
|
|
128
|
+
const platformIdle = new PlatformIdleScheduler(ctx, cfg, states);
|
|
129
|
+
// ===== mutedUntil 持久化(仅此字段) =====
|
|
130
|
+
// 其他运行时态(cooldownUntil/replyTimestamps/activityScore等)都是秒级短期,
|
|
131
|
+
// 重启后重建无危;但 mutedUntil 可能是小时级的「用户意图」,丢失会导致重启后静默解除。
|
|
132
|
+
const storage = createStorageGateway(ctx);
|
|
133
|
+
const muteStateUri = 'data:/flow-control-mutes.json';
|
|
134
|
+
async function loadMuteState() {
|
|
135
|
+
try {
|
|
136
|
+
let raw;
|
|
137
|
+
try {
|
|
138
|
+
raw = (await storage.readFile(muteStateUri, 'utf-8'));
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const data = JSON.parse(raw);
|
|
144
|
+
if (!data || typeof data !== 'object')
|
|
145
|
+
return;
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
let restored = 0;
|
|
148
|
+
for (const [sessionId, entry] of Object.entries(data)) {
|
|
149
|
+
const mutedUntil = Number(entry?.mutedUntil ?? 0);
|
|
150
|
+
if (!mutedUntil || mutedUntil <= now)
|
|
151
|
+
continue;
|
|
152
|
+
const platform = String(entry?.platform ?? '');
|
|
153
|
+
const s = createState(platform);
|
|
154
|
+
s.mutedUntil = mutedUntil;
|
|
155
|
+
states.set(sessionId, s);
|
|
156
|
+
restored++;
|
|
157
|
+
}
|
|
158
|
+
if (restored > 0)
|
|
159
|
+
ctx.logger.info(`[flow] 已恢复 ${restored} 个未过期的禁言状态`);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
ctx.logger.warn(`[flow] 加载禁言状态失败: ${err}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
let saveChain = Promise.resolve();
|
|
166
|
+
function saveMuteState() {
|
|
167
|
+
const now = Date.now();
|
|
168
|
+
const out = {};
|
|
169
|
+
for (const [sessionId, s] of states.entries()) {
|
|
170
|
+
if (s.mutedUntil > now)
|
|
171
|
+
out[sessionId] = { platform: s.platform ?? '', mutedUntil: s.mutedUntil };
|
|
172
|
+
}
|
|
173
|
+
const payload = JSON.stringify(out, null, 2);
|
|
174
|
+
saveChain = saveChain
|
|
175
|
+
.then(() => storage.writeFile(muteStateUri, payload))
|
|
176
|
+
.catch(err => {
|
|
177
|
+
ctx.logger.warn(`[flow] 持久化禁言状态失败: ${err}`);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
await loadMuteState();
|
|
181
|
+
/** 从 IncomingMessage 派生 per-scope override 用的 targetId(群=groupId / 私=userId / 其他=空) */
|
|
182
|
+
function extractTargetId(message) {
|
|
183
|
+
if (message.sessionType === 'group')
|
|
184
|
+
return message.groupId ?? '';
|
|
185
|
+
if (message.sessionType === 'private')
|
|
186
|
+
return message.userId ?? '';
|
|
187
|
+
return '';
|
|
188
|
+
}
|
|
189
|
+
function getOrCreate(sessionId, platform, sessionType = '', targetId = '') {
|
|
190
|
+
let s = states.get(sessionId);
|
|
191
|
+
if (!s) {
|
|
192
|
+
s = createState(platform, sessionType, targetId);
|
|
193
|
+
states.set(sessionId, s);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
if (!s.platform && platform)
|
|
197
|
+
s.platform = platform;
|
|
198
|
+
if (!s.sessionType && sessionType)
|
|
199
|
+
s.sessionType = sessionType;
|
|
200
|
+
if (!s.targetId && targetId)
|
|
201
|
+
s.targetId = targetId;
|
|
202
|
+
}
|
|
203
|
+
return s;
|
|
204
|
+
}
|
|
205
|
+
/** 按 state 上下文解析生效 cfg(应用 overrides) */
|
|
206
|
+
function eff(s) {
|
|
207
|
+
if (!s)
|
|
208
|
+
return cfg;
|
|
209
|
+
return resolveEffectiveConfig(cfg, s.platform, s.sessionType, s.targetId);
|
|
210
|
+
}
|
|
211
|
+
function logStatus(sessionId, s, label) {
|
|
212
|
+
const e = eff(s);
|
|
213
|
+
const threshold = getCurrentThreshold(s, e);
|
|
214
|
+
ctx.logger.debug(`[flow] ${label} | session=${sessionId} | ` +
|
|
215
|
+
`计数=${s.messageCount}/${e.fixedInterval} | ` +
|
|
216
|
+
`指数=${s.activityScore.toFixed(3)} (阈值=${threshold.toFixed(3)})`);
|
|
217
|
+
}
|
|
218
|
+
/** 把"被流控吞掉"的入站消息归档到 message-archive,下次触发时作为上下文 */
|
|
219
|
+
async function shadowArchive(message) {
|
|
220
|
+
const archive = ctx.getService('message-archive');
|
|
221
|
+
if (!archive)
|
|
222
|
+
return;
|
|
223
|
+
try {
|
|
224
|
+
await archive.archiveIncoming(message);
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
ctx.logger.warn(`[flow] shadow 归档失败: ${err}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ===== Service 实现 =====
|
|
231
|
+
const service = {
|
|
232
|
+
ensureState(sessionId, platform, sessionType, targetId) {
|
|
233
|
+
getOrCreate(sessionId, platform, sessionType, targetId);
|
|
234
|
+
},
|
|
235
|
+
getStateSnapshot(sessionId) {
|
|
236
|
+
const s = states.get(sessionId);
|
|
237
|
+
return s ? snapshot(s, eff(s)) : undefined;
|
|
238
|
+
},
|
|
239
|
+
recordIncoming(sessionId, platform, userId, sessionType, targetId) {
|
|
240
|
+
const s = getOrCreate(sessionId, platform, sessionType, targetId);
|
|
241
|
+
const e = eff(s);
|
|
242
|
+
const now = Date.now();
|
|
243
|
+
applyScoreDecay(s, e);
|
|
244
|
+
if (userId) {
|
|
245
|
+
const prev = s.userInteractions.get(userId) ?? { count: 0, lastTime: 0 };
|
|
246
|
+
s.userInteractions.set(userId, { count: prev.count + 1, lastTime: now });
|
|
247
|
+
}
|
|
248
|
+
s.lastMessageTime = now;
|
|
249
|
+
s.messageCount++;
|
|
250
|
+
s.activityScore += calculateScoreIncrement(s, e, userId);
|
|
251
|
+
},
|
|
252
|
+
recordTriggered(sessionId) {
|
|
253
|
+
const s = states.get(sessionId);
|
|
254
|
+
if (!s)
|
|
255
|
+
return;
|
|
256
|
+
s.messageCount = 0;
|
|
257
|
+
s.activityScore = 0;
|
|
258
|
+
s.lastReplyTime = Date.now();
|
|
259
|
+
s.idleBackoff = 1;
|
|
260
|
+
},
|
|
261
|
+
recordReply(sessionId, platform) {
|
|
262
|
+
const s = getOrCreate(sessionId, platform);
|
|
263
|
+
const e = eff(s);
|
|
264
|
+
if (e.cooldownSeconds > 0) {
|
|
265
|
+
s.cooldownUntil = Date.now() + e.cooldownSeconds * 1000;
|
|
266
|
+
}
|
|
267
|
+
s.idleBackoff = 1;
|
|
268
|
+
s.replyTimestamps.push(Date.now());
|
|
269
|
+
this.rescheduleIdle(sessionId, platform);
|
|
270
|
+
},
|
|
271
|
+
isCoolingDown(sessionId) {
|
|
272
|
+
const s = states.get(sessionId);
|
|
273
|
+
return !!s && Date.now() < s.cooldownUntil;
|
|
274
|
+
},
|
|
275
|
+
isMuted(sessionId) {
|
|
276
|
+
const s = states.get(sessionId);
|
|
277
|
+
return !!s && Date.now() < s.mutedUntil;
|
|
278
|
+
},
|
|
279
|
+
isRateLimited(sessionId) {
|
|
280
|
+
const s = states.get(sessionId);
|
|
281
|
+
if (!s)
|
|
282
|
+
return false;
|
|
283
|
+
const e = eff(s);
|
|
284
|
+
if (e.rateLimitWindow <= 0 || e.rateLimitMaxReplies <= 0)
|
|
285
|
+
return false;
|
|
286
|
+
return rateLimitUsedNow(s, e) >= e.rateLimitMaxReplies;
|
|
287
|
+
},
|
|
288
|
+
setMuted(sessionId, durationSec, platform) {
|
|
289
|
+
let s = states.get(sessionId);
|
|
290
|
+
if (!s && platform && durationSec > 0) {
|
|
291
|
+
s = getOrCreate(sessionId, platform);
|
|
292
|
+
}
|
|
293
|
+
if (!s)
|
|
294
|
+
return;
|
|
295
|
+
if (durationSec <= 0) {
|
|
296
|
+
s.mutedUntil = 0;
|
|
297
|
+
saveMuteState();
|
|
298
|
+
ctx.logger.info(`[flow] 已解除自禁言: session=${sessionId}`);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
s.mutedUntil = Date.now() + durationSec * 1000;
|
|
302
|
+
s.messageCount = 0;
|
|
303
|
+
s.activityScore = 0;
|
|
304
|
+
clearSessionIdle(s);
|
|
305
|
+
saveMuteState();
|
|
306
|
+
ctx.logger.info(`[flow] 已设置自禁言: session=${sessionId}, ${durationSec}s`);
|
|
307
|
+
},
|
|
308
|
+
getThreshold(sessionId) {
|
|
309
|
+
const s = states.get(sessionId);
|
|
310
|
+
if (!s)
|
|
311
|
+
return cfg.activityScoreLower;
|
|
312
|
+
return getCurrentThreshold(s, eff(s));
|
|
313
|
+
},
|
|
314
|
+
rescheduleIdle(sessionId, platform) {
|
|
315
|
+
const s = states.get(sessionId);
|
|
316
|
+
if (!s)
|
|
317
|
+
return;
|
|
318
|
+
scheduleSessionIdle(ctx, eff(s), s, sessionId, platform, () => this.rescheduleIdle(sessionId, platform));
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
ctx.provide('flow-control', service);
|
|
322
|
+
ctx.logger.info(`[flow] 已启用 (固定间隔=${cfg.fixedInterval}, 阈值=${cfg.activityScoreLower}~${cfg.activityScoreUpper}, ` +
|
|
323
|
+
`冷却=${cfg.cooldownSeconds}s, 限速=${cfg.rateLimitWindow}s/${cfg.rateLimitMaxReplies}次, ` +
|
|
324
|
+
`idle=${cfg.idleTriggerScope}/${cfg.idleTriggerStrategy}, scopes=${cfg.scopes.join('|') || '<空>'}, ` +
|
|
325
|
+
`overrides=${cfg.overrides.length})`);
|
|
326
|
+
// ===== inbound:flow 相位:流控前置闸门 =====
|
|
327
|
+
// 由 plugin-gateway 在 inbound:command 之后、inbound:trigger 之前触发。
|
|
328
|
+
// 默认 scopes=['*:group'] 与历史 OneBot ChatFlow 行为一致;
|
|
329
|
+
// overrides 中任一 scope 命中也视为启用(用于 *:private 等单独覆盖场景)。
|
|
330
|
+
ctx.middleware(INBOUND_PHASE.FLOW, async (data, next) => {
|
|
331
|
+
const { message } = data;
|
|
332
|
+
if (!isScopeEnabled(cfg, message.platform, message.sessionType, extractTargetId(message)))
|
|
333
|
+
return next();
|
|
334
|
+
if (message.source === 'idle-trigger')
|
|
335
|
+
return next(); // 内部注入不再过流控
|
|
336
|
+
const targetId = extractTargetId(message);
|
|
337
|
+
service.ensureState(message.sessionId, message.platform, message.sessionType, targetId);
|
|
338
|
+
service.recordIncoming(message.sessionId, message.platform, message.userId, message.sessionType, targetId);
|
|
339
|
+
const s = states.get(message.sessionId);
|
|
340
|
+
if (service.isMuted(message.sessionId)) {
|
|
341
|
+
// 禁言期不重置 idle timer:避免在禁言结束后被立即唤醒重复触发。
|
|
342
|
+
logStatus(message.sessionId, s, '禁言中 → 吞噬');
|
|
343
|
+
await shadowArchive(message);
|
|
344
|
+
return; // swallow
|
|
345
|
+
}
|
|
346
|
+
if (service.isCoolingDown(message.sessionId)) {
|
|
347
|
+
logStatus(message.sessionId, s, '冷却中 → 吞噬');
|
|
348
|
+
await shadowArchive(message);
|
|
349
|
+
service.rescheduleIdle(message.sessionId, message.platform);
|
|
350
|
+
return; // swallow
|
|
351
|
+
}
|
|
352
|
+
if (service.isRateLimited(message.sessionId)) {
|
|
353
|
+
logStatus(message.sessionId, s, '限速 → 吞噬');
|
|
354
|
+
await shadowArchive(message);
|
|
355
|
+
service.rescheduleIdle(message.sessionId, message.platform);
|
|
356
|
+
return; // swallow
|
|
357
|
+
}
|
|
358
|
+
// 通过流控前置闸门:交给下一相位(inbound:trigger → inbound:dispatch)
|
|
359
|
+
await next();
|
|
360
|
+
});
|
|
361
|
+
// 出站消息后记录冷却 / 重置退避(同样仅对群会话计入流控)
|
|
362
|
+
ctx.on('outbound:message', (msg) => {
|
|
363
|
+
if (!msg.sessionId)
|
|
364
|
+
return;
|
|
365
|
+
if (msg.source !== 'agent')
|
|
366
|
+
return; // 命令/系统回复不算"对话回复"
|
|
367
|
+
const s = states.get(msg.sessionId);
|
|
368
|
+
if (!s)
|
|
369
|
+
return; // 没有 state 说明该 session 从未走过群流控(私聊/CLI 等),跳过
|
|
370
|
+
service.recordReply(msg.sessionId, s.platform);
|
|
371
|
+
});
|
|
372
|
+
// 平台级 idle 启动
|
|
373
|
+
ctx.on('ready', () => {
|
|
374
|
+
platformIdle.start();
|
|
375
|
+
});
|
|
376
|
+
// 长寿进程下避免 states 无限增长:每天扫描一次,清理 30 天未活动且无禁言/冷却挂起的会话
|
|
377
|
+
const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
378
|
+
const SWEEP_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
379
|
+
const sweepTimer = setInterval(() => {
|
|
380
|
+
const now = Date.now();
|
|
381
|
+
let cleaned = 0;
|
|
382
|
+
for (const [sid, s] of states) {
|
|
383
|
+
const lastActive = Math.max(s.lastMessageTime, s.lastReplyTime);
|
|
384
|
+
const hasPending = s.mutedUntil > now || s.cooldownUntil > now || !!s.idleTimer;
|
|
385
|
+
if (!hasPending && lastActive > 0 && now - lastActive > SESSION_TTL_MS) {
|
|
386
|
+
clearSessionIdle(s);
|
|
387
|
+
states.delete(sid);
|
|
388
|
+
cleaned++;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (cleaned > 0)
|
|
392
|
+
ctx.logger.debug(`[flow] TTL 清理已淘汰 ${cleaned} 个长期非活跃会话状态`);
|
|
393
|
+
}, SWEEP_INTERVAL_MS);
|
|
394
|
+
if (typeof sweepTimer.unref === 'function')
|
|
395
|
+
sweepTimer.unref();
|
|
396
|
+
ctx.onDispose(() => {
|
|
397
|
+
clearInterval(sweepTimer);
|
|
398
|
+
platformIdle.stop();
|
|
399
|
+
for (const s of states.values())
|
|
400
|
+
clearSessionIdle(s);
|
|
401
|
+
states.clear();
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { FlowControlConfig } from './config.js';
|
|
2
|
+
import type { FlowSessionStateSnapshot } from './types.js';
|
|
3
|
+
export interface MutableFlowSessionState {
|
|
4
|
+
messageCount: number;
|
|
5
|
+
lastReplyTime: number;
|
|
6
|
+
lastMessageTime: number;
|
|
7
|
+
activityScore: number;
|
|
8
|
+
cooldownUntil: number;
|
|
9
|
+
mutedUntil: number;
|
|
10
|
+
idleTimer: ReturnType<typeof setTimeout> | null;
|
|
11
|
+
idleBackoff: number;
|
|
12
|
+
userInteractions: Map<string, {
|
|
13
|
+
count: number;
|
|
14
|
+
lastTime: number;
|
|
15
|
+
}>;
|
|
16
|
+
/** 滑动窗口内的回复时间戳(用于防 DDoS 限速) */
|
|
17
|
+
replyTimestamps: number[];
|
|
18
|
+
/** 该 session 所属 platform(首次记录时设置;用于 idle 调度找回) */
|
|
19
|
+
platform: string;
|
|
20
|
+
/** 该 session 的 sessionType(如 group/private/channel);用于 per-scope 覆盖匹配 */
|
|
21
|
+
sessionType: string;
|
|
22
|
+
/** 该 session 的目标 id(群号/用户号/频道号);用于 per-scope 覆盖匹配 */
|
|
23
|
+
targetId: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function createState(platform: string, sessionType?: string, targetId?: string): MutableFlowSessionState;
|
|
26
|
+
/** 当前阈值(动态衰减) */
|
|
27
|
+
export declare function getCurrentThreshold(state: MutableFlowSessionState, cfg: FlowControlConfig): number;
|
|
28
|
+
/** 评分按距离上次消息的时间线性衰减(原地修改) */
|
|
29
|
+
export declare function applyScoreDecay(state: MutableFlowSessionState, cfg: FlowControlConfig): void;
|
|
30
|
+
/** 计算单条入站对评分的增量(受用户交互权重影响) */
|
|
31
|
+
export declare function calculateScoreIncrement(state: MutableFlowSessionState, cfg: FlowControlConfig, userId?: string): number;
|
|
32
|
+
export declare function rateLimitUsedNow(state: MutableFlowSessionState, cfg: FlowControlConfig): number;
|
|
33
|
+
export declare function snapshot(state: MutableFlowSessionState, cfg: FlowControlConfig): FlowSessionStateSnapshot;
|
|
34
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,+BAA+B;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,SAAK,EAAE,QAAQ,SAAK,GAAG,uBAAuB,CAgBtG;AAED,iBAAiB;AACjB,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,uBAAuB,EAAE,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAMlG;AAED,6BAA6B;AAC7B,wBAAgB,eAAe,CAAC,KAAK,EAAE,uBAAuB,EAAE,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAO5F;AAED,8BAA8B;AAC9B,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,EAC9B,GAAG,EAAE,iBAAiB,EACtB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAUR;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,uBAAuB,EAAE,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAI/F;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,uBAAuB,EAAE,GAAG,EAAE,iBAAiB,GAAG,wBAAwB,CAczG"}
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// ----- FlowSessionState 内部实现 + 衰减/计数算法 -----
|
|
2
|
+
export function createState(platform, sessionType = '', targetId = '') {
|
|
3
|
+
return {
|
|
4
|
+
messageCount: 0,
|
|
5
|
+
lastReplyTime: 0,
|
|
6
|
+
lastMessageTime: 0,
|
|
7
|
+
activityScore: 0,
|
|
8
|
+
cooldownUntil: 0,
|
|
9
|
+
mutedUntil: 0,
|
|
10
|
+
idleTimer: null,
|
|
11
|
+
idleBackoff: 1,
|
|
12
|
+
userInteractions: new Map(),
|
|
13
|
+
replyTimestamps: [],
|
|
14
|
+
platform,
|
|
15
|
+
sessionType,
|
|
16
|
+
targetId,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** 当前阈值(动态衰减) */
|
|
20
|
+
export function getCurrentThreshold(state, cfg) {
|
|
21
|
+
if (state.lastReplyTime === 0)
|
|
22
|
+
return cfg.activityScoreLower;
|
|
23
|
+
const elapsed = Date.now() - state.lastReplyTime;
|
|
24
|
+
const decayMs = cfg.activityDecayMinutes * 60 * 1000;
|
|
25
|
+
const factor = Math.max(0, 1 - elapsed / decayMs);
|
|
26
|
+
return cfg.activityScoreLower + (cfg.activityScoreUpper - cfg.activityScoreLower) * factor;
|
|
27
|
+
}
|
|
28
|
+
/** 评分按距离上次消息的时间线性衰减(原地修改) */
|
|
29
|
+
export function applyScoreDecay(state, cfg) {
|
|
30
|
+
if (cfg.scoreDecayMinutes <= 0 || state.activityScore <= 0 || state.lastMessageTime === 0)
|
|
31
|
+
return;
|
|
32
|
+
const elapsed = Date.now() - state.lastMessageTime;
|
|
33
|
+
const decayMs = cfg.scoreDecayMinutes * 60 * 1000;
|
|
34
|
+
const factor = Math.max(0, 1 - elapsed / decayMs);
|
|
35
|
+
state.activityScore *= factor;
|
|
36
|
+
if (state.activityScore < 0.001)
|
|
37
|
+
state.activityScore = 0;
|
|
38
|
+
}
|
|
39
|
+
/** 计算单条入站对评分的增量(受用户交互权重影响) */
|
|
40
|
+
export function calculateScoreIncrement(state, cfg, userId) {
|
|
41
|
+
const base = 1.0 / Math.max(1, cfg.fixedInterval);
|
|
42
|
+
let userWeight = 1.0;
|
|
43
|
+
if (userId) {
|
|
44
|
+
const interaction = state.userInteractions.get(userId);
|
|
45
|
+
if (interaction) {
|
|
46
|
+
userWeight = 1.0 + 0.5 * Math.min(interaction.count / 10, 1.0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return base * userWeight;
|
|
50
|
+
}
|
|
51
|
+
export function rateLimitUsedNow(state, cfg) {
|
|
52
|
+
if (cfg.rateLimitWindow <= 0)
|
|
53
|
+
return 0;
|
|
54
|
+
const windowStart = Date.now() - cfg.rateLimitWindow * 1000;
|
|
55
|
+
return state.replyTimestamps.filter(t => t > windowStart).length;
|
|
56
|
+
}
|
|
57
|
+
export function snapshot(state, cfg) {
|
|
58
|
+
return {
|
|
59
|
+
messageCount: state.messageCount,
|
|
60
|
+
activityScore: state.activityScore,
|
|
61
|
+
lastReplyTime: state.lastReplyTime,
|
|
62
|
+
lastMessageTime: state.lastMessageTime,
|
|
63
|
+
cooldownUntil: state.cooldownUntil,
|
|
64
|
+
mutedUntil: state.mutedUntil,
|
|
65
|
+
idleBackoff: state.idleBackoff,
|
|
66
|
+
rateLimitUsed: rateLimitUsedNow(state, cfg),
|
|
67
|
+
rateLimitMax: cfg.rateLimitMaxReplies,
|
|
68
|
+
fixedInterval: cfg.fixedInterval,
|
|
69
|
+
userInteractions: state.userInteractions,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aalis/plugin-flow-control",
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "平台无关流控:禁言/冷却/限速/闲置触发",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"aalis",
|
|
9
|
+
"aalis-plugin"
|
|
10
|
+
],
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@aalis/plugin-flow-control-api": "workspace:^",
|
|
22
|
+
"@aalis/plugin-gateway-api": "workspace:^",
|
|
23
|
+
"@aalis/plugin-message-api": "workspace:^",
|
|
24
|
+
"@aalis/plugin-storage-api": "workspace:^"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@aalis/core": "workspace:*",
|
|
28
|
+
"@aalis/plugin-message-archive-api": "workspace:*",
|
|
29
|
+
"@aalis/plugin-webui-api": "workspace:*",
|
|
30
|
+
"@types/node": "^22.0.0",
|
|
31
|
+
"typescript": "^5.7.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@aalis/core": ">=0.2.0 <1.0.0"
|
|
35
|
+
},
|
|
36
|
+
"aalis": {
|
|
37
|
+
"service": {
|
|
38
|
+
"required": [
|
|
39
|
+
"gateway"
|
|
40
|
+
],
|
|
41
|
+
"optional": [
|
|
42
|
+
"message-archive"
|
|
43
|
+
],
|
|
44
|
+
"provides": [
|
|
45
|
+
"flow-control"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|