@qing3a/flow-rpa-engine 0.3.0 → 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/dist/behavior.d.ts +272 -0
- package/dist/behavior.js +367 -0
- package/dist/behavior.js.map +1 -0
- package/dist/cdp/page.d.ts +31 -2
- package/dist/cdp/page.js +428 -8
- package/dist/cdp/page.js.map +1 -1
- package/dist/executor.d.ts +38 -0
- package/dist/executor.js +167 -13
- package/dist/executor.js.map +1 -1
- package/dist/export.js +9 -2
- package/dist/export.js.map +1 -1
- package/dist/gate.d.ts +9 -3
- package/dist/gate.js +19 -7
- package/dist/gate.js.map +1 -1
- package/dist/human.js +89 -24
- package/dist/human.js.map +1 -1
- package/dist/learning.d.ts +47 -3
- package/dist/learning.js +121 -8
- package/dist/learning.js.map +1 -1
- package/dist/platform.d.ts +3 -0
- package/dist/platform.js +58 -13
- package/dist/platform.js.map +1 -1
- package/dist/record.d.ts +3 -3
- package/dist/record.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 行为档案(Behavior Archive)—— 记忆层(docs/BEHAVIOR-SPACE.md)。
|
|
3
|
+
*
|
|
4
|
+
* 定位:引擎对页面交互行为规律的语义化知识库。在流程执行时旁路观察
|
|
5
|
+
* (点击/输入前后页面功能区出现/消失、延迟、文本变化),积累成语义化档案,
|
|
6
|
+
* 供 L2(learning.ts)消费,产出自动修正建议(机器安全门替代人工确认)。
|
|
7
|
+
*
|
|
8
|
+
* 数据形态(纯语义,无坐标、无原文):
|
|
9
|
+
* 每次动作一条记录,包含:动作信息(type/selectorHit)、触发前后页面状态
|
|
10
|
+
* (功能区文本哈希、URL 路由、文本变化)、结果(成败/耗时)。
|
|
11
|
+
* selector/target 文本落盘时掩码(掩码前移原则,不存敏感原文)。
|
|
12
|
+
*/
|
|
13
|
+
/** 一次动作的行为观察记录(纯语义,无坐标) */
|
|
14
|
+
export interface BehaviorEntry {
|
|
15
|
+
/** 记录类型(与 events.jsonl 的 action_footprint 同构;行为档案用独立文件) */
|
|
16
|
+
type: 'behavior_observation';
|
|
17
|
+
/** 来源流程 id(建议归属依据:行为建议挂到数据来源的 flow 下,而非当前 run 的 flow) */
|
|
18
|
+
flowId: string;
|
|
19
|
+
runId: string;
|
|
20
|
+
stepId: string;
|
|
21
|
+
/** 动作类型:click / input / navigate / extract */
|
|
22
|
+
actionType: string;
|
|
23
|
+
/** 选择器原文(掩码后;含数组链中实际命中的下标) */
|
|
24
|
+
selector: string;
|
|
25
|
+
selectorHit: string;
|
|
26
|
+
/** 动作前页面状态(语义摘要) */
|
|
27
|
+
before: {
|
|
28
|
+
/** URL 路由键(host+path,无 query——SPA query 变化不算路由跳转) */
|
|
29
|
+
route: string;
|
|
30
|
+
/** 页面文本哈希(变化检测用,不存原文) */
|
|
31
|
+
textHash: string;
|
|
32
|
+
/** 页面文本长度 */
|
|
33
|
+
textLen: number;
|
|
34
|
+
};
|
|
35
|
+
/** 动作后页面状态(语义摘要) */
|
|
36
|
+
after: {
|
|
37
|
+
route: string;
|
|
38
|
+
textHash: string;
|
|
39
|
+
textLen: number;
|
|
40
|
+
};
|
|
41
|
+
/** 前后差异(转移层,浅层 diff) */
|
|
42
|
+
delta: {
|
|
43
|
+
routeChanged: boolean;
|
|
44
|
+
textChanged: boolean;
|
|
45
|
+
textDeltaLen: number;
|
|
46
|
+
};
|
|
47
|
+
/** 动作结果 */
|
|
48
|
+
result: {
|
|
49
|
+
ok: boolean;
|
|
50
|
+
error: string;
|
|
51
|
+
durationMs: number;
|
|
52
|
+
};
|
|
53
|
+
/** 区域快照(P2:动作目标所在区域;由采集时区域识别填充) */
|
|
54
|
+
region?: RegionSnapshot;
|
|
55
|
+
/**
|
|
56
|
+
* 命中元素指纹(P3 语义锚点:动作成功时目标元素的语义特征,供选择器失效时
|
|
57
|
+
* 生成替代定位。无原文、无坐标——只有 tag/文本截断/属性名,符合掩码前移)。
|
|
58
|
+
*/
|
|
59
|
+
hitEl?: HitFingerprint;
|
|
60
|
+
at: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 命中元素指纹(P3 语义锚点数据源):
|
|
64
|
+
* 元素可重定位的语义特征(不含坐标/URL/输入值)。全部字段可选——有多少记多少。
|
|
65
|
+
*/
|
|
66
|
+
export interface HitFingerprint {
|
|
67
|
+
/** 标签名(小写,如 button/a/input) */
|
|
68
|
+
tag?: string;
|
|
69
|
+
/** 元素文本(≤30 截断;按钮/链接型锚点用) */
|
|
70
|
+
text?: string;
|
|
71
|
+
/** placeholder 属性(输入框型锚点用) */
|
|
72
|
+
placeholder?: string;
|
|
73
|
+
/** aria-label 属性(无障碍锚点) */
|
|
74
|
+
ariaLabel?: string;
|
|
75
|
+
/** name 属性(表单锚点) */
|
|
76
|
+
name?: string;
|
|
77
|
+
/** 所在区域标签(P2 region.label;锚点可按区域约束的候选来源) */
|
|
78
|
+
region?: string;
|
|
79
|
+
}
|
|
80
|
+
/** 语义锚点聚合(profile 内:指纹去重累加 count——一致出现次数 = 可信度) */
|
|
81
|
+
export interface AnchorAgg {
|
|
82
|
+
fp: HitFingerprint;
|
|
83
|
+
/** 该指纹一致出现的次数(机器安全门:≥2 才生成替代选择器) */
|
|
84
|
+
count: number;
|
|
85
|
+
lastAt: string;
|
|
86
|
+
}
|
|
87
|
+
/** 锚点指纹键(去重依据;tag 并入降低跨类型误并) */
|
|
88
|
+
export declare function anchorKey(fp: HitFingerprint): string;
|
|
89
|
+
/** P3 锚点聚合上限(每 step|action 保留的锚点数;防无限增长) */
|
|
90
|
+
export declare const PROFILE_MAX_ANCHORS = 5;
|
|
91
|
+
/** 语义锚点:最少一致出现次数(机器安全门:≥2 才可信,替代人工确认) */
|
|
92
|
+
export declare const ANCHOR_MIN_COUNT = 2;
|
|
93
|
+
/** 每次动作最多尝试的锚点选择器数(保底降级链长度) */
|
|
94
|
+
export declare const ANCHOR_MAX_SELECTORS = 4;
|
|
95
|
+
/**
|
|
96
|
+
* P3 聚合锚点(纯函数,可单测):按指纹键去重,同键 count+1 并更新 lastAt(置前);
|
|
97
|
+
* 新键 count=1。超过上限丢最旧(数组尾部)。新增/更新在前(最近命中优先排序依据)。
|
|
98
|
+
*/
|
|
99
|
+
export declare function mergeAnchor(anchors: AnchorAgg[], fp: HitFingerprint, at: string): AnchorAgg[];
|
|
100
|
+
/**
|
|
101
|
+
* P3 生成语义锚点选择器(纯函数,可单测):count ≥ ANCHOR_MIN_COUNT 的锚点,
|
|
102
|
+
* 按 count 降序生成 getBySels 兼容选择器(text: 精确文本 / placeholder / aria-label / name)。
|
|
103
|
+
* 返回空数组 = 档案不足(不增强,走原错误路径)。引擎零业务逻辑——只做定位框架。
|
|
104
|
+
*/
|
|
105
|
+
export declare function buildAnchorSelectors(anchors: AnchorAgg[] | undefined): string[];
|
|
106
|
+
/** 简易文本哈希(FNV-1a 32 位;仅用于变化检测,非加密) */
|
|
107
|
+
export declare function textHash(s: string): string;
|
|
108
|
+
/** 路由键(host+path,忽略 query/hash) */
|
|
109
|
+
export declare function routeKey(u: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* 区域识别规则(behavior.rules.json,随流程包分发——引擎零业务逻辑铁律)。
|
|
112
|
+
* 引擎只提供规则执行框架:加载 rules → 匹配目标元素祖先 → 打区域标签。
|
|
113
|
+
*/
|
|
114
|
+
export interface RegionRule {
|
|
115
|
+
/** 规则 id(唯一) */
|
|
116
|
+
id: string;
|
|
117
|
+
/** 匹配条件(全部满足才算命中;缺省字段不参与匹配) */
|
|
118
|
+
match: {
|
|
119
|
+
/** 区域文本包含关键词(如「职位描述」→ 详情区) */
|
|
120
|
+
textContains?: string;
|
|
121
|
+
/** 区域文本包含全部关键词(多条件精确匹配,如「职位描述」+「任职要求」才认详情区) */
|
|
122
|
+
textContainsAll?: string[];
|
|
123
|
+
/** 区域内含输入框(input/textarea)→ 搜索区等 */
|
|
124
|
+
hasInput?: boolean;
|
|
125
|
+
/** 区域内含按钮(button/a[role=button]) */
|
|
126
|
+
hasButton?: boolean;
|
|
127
|
+
/** 祖先标签(header/nav/main/aside/footer) */
|
|
128
|
+
ancestorTag?: string;
|
|
129
|
+
/** 祖先 class 包含(如卡片在 rec-job-list 内 → 列表区) */
|
|
130
|
+
ancestorClass?: string;
|
|
131
|
+
};
|
|
132
|
+
/** 命中后打的区域标签(如「详情区」/「搜索区」) */
|
|
133
|
+
label: string;
|
|
134
|
+
}
|
|
135
|
+
/** 行为规则文件(flows/<flowId>/behavior.rules.json) */
|
|
136
|
+
export interface BehaviorRules {
|
|
137
|
+
rulesVersion: number;
|
|
138
|
+
regionRules: RegionRule[];
|
|
139
|
+
}
|
|
140
|
+
/** 区域特征(P2 规则匹配输入:DOM 侧收集的祖先层特征) */
|
|
141
|
+
export interface RegionFeatures {
|
|
142
|
+
/** 元素文本(祖先 innerText) */
|
|
143
|
+
text: string;
|
|
144
|
+
/** 是否含输入框 */
|
|
145
|
+
hasInput: boolean;
|
|
146
|
+
/** 是否含按钮 */
|
|
147
|
+
hasButton: boolean;
|
|
148
|
+
/** 标签名(小写) */
|
|
149
|
+
tag: string;
|
|
150
|
+
/** class 字符串 */
|
|
151
|
+
cls: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* P2 规则匹配(纯函数,可单测):规则的全部 match 条件满足才命中。
|
|
155
|
+
* 引擎零业务逻辑——规则来自 behavior.rules.json,这里只执行匹配框架。
|
|
156
|
+
*/
|
|
157
|
+
export declare function matchRegionRule(rule: RegionRule, f: RegionFeatures): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* P2 区域识别(纯函数,可单测):对每层祖先特征依次用规则匹配,命中即返回。
|
|
160
|
+
* 返回 { label, ruleId };无命中 → null。
|
|
161
|
+
*/
|
|
162
|
+
export declare function identifyRegionFromFeatures(rules: RegionRule[], features: RegionFeatures[]): {
|
|
163
|
+
label: string;
|
|
164
|
+
ruleId: string;
|
|
165
|
+
} | null;
|
|
166
|
+
/** 行为档案:区域快照(P2:动作目标所在区域的语义描述) */
|
|
167
|
+
export interface RegionSnapshot {
|
|
168
|
+
/** 区域标签(如「详情区」/「搜索区」;无规则命中 → undefined) */
|
|
169
|
+
label?: string;
|
|
170
|
+
/** 命中规则的 id */
|
|
171
|
+
ruleId?: string;
|
|
172
|
+
/** 目标元素的祖先链摘要(top 3,tag.cls)——抗改版重定位用 */
|
|
173
|
+
ancestry?: string[];
|
|
174
|
+
}
|
|
175
|
+
/** 每步骤/动作的耗时统计(预测性超时数据源;p50/p95 防极端值) */
|
|
176
|
+
export interface TimingStat {
|
|
177
|
+
samples: number;
|
|
178
|
+
avgDurationMs: number;
|
|
179
|
+
p50Ms: number;
|
|
180
|
+
p95Ms: number;
|
|
181
|
+
}
|
|
182
|
+
/** 状态档案(增量合并,原子写):按 步骤|动作 聚合 timing + 计数 */
|
|
183
|
+
export interface RegionProfile {
|
|
184
|
+
/** schema 版本(未来升级迁移用;当前 v1) */
|
|
185
|
+
schemaVersion: 1;
|
|
186
|
+
flowId: string;
|
|
187
|
+
updatedAt: string;
|
|
188
|
+
/** stepId → actionType → 统计(含 seen 置信度与 timing) */
|
|
189
|
+
steps: Record<string, Record<string, {
|
|
190
|
+
seen: number;
|
|
191
|
+
timing?: TimingStat;
|
|
192
|
+
anchors?: AnchorAgg[];
|
|
193
|
+
}>>;
|
|
194
|
+
/** 区域出现统计(P2):label → seen(区域功能模型的置信度) */
|
|
195
|
+
regions?: Record<string, {
|
|
196
|
+
seen: number;
|
|
197
|
+
ruleId?: string;
|
|
198
|
+
}>;
|
|
199
|
+
}
|
|
200
|
+
/** 当前 profile schema 版本(升级时 bump + 迁移) */
|
|
201
|
+
export declare const PROFILE_SCHEMA_VERSION: 1;
|
|
202
|
+
/** 状态档案:每步骤保留的最大耗时样本数(防无限增长;超了丢最旧) */
|
|
203
|
+
export declare const PROFILE_MAX_SAMPLES = 50;
|
|
204
|
+
/** 简易互斥锁(单进程内读-合并-写原子化;--http 多请求并发安全) */
|
|
205
|
+
export declare class Mutex {
|
|
206
|
+
private tail;
|
|
207
|
+
run<T>(fn: () => T | Promise<T>): Promise<T>;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* 行为档案库:内存积累 + 落盘 JSONL(data/behavior/archive.jsonl,幂等追加)+ 状态档案
|
|
211
|
+
* (data/behavior/profiles/<flowId>.json,增量合并+原子写+互斥锁)。
|
|
212
|
+
* 单例由 app 层持有(与 RunStore 同级),run 期间通过 onBehavior 回调喂入。
|
|
213
|
+
*/
|
|
214
|
+
export declare class BehaviorArchive {
|
|
215
|
+
private entries;
|
|
216
|
+
private file;
|
|
217
|
+
private profilesDir;
|
|
218
|
+
/** 状态档案内存缓存(flowId → profile);读-合并-写经互斥锁原子化 */
|
|
219
|
+
private profileCache;
|
|
220
|
+
/** 每步骤耗时样本(内存:stepId|actionType → sorted 数组),用于 p50/p95 */
|
|
221
|
+
private samplesCache;
|
|
222
|
+
/** 读-合并-写互斥锁(并发安全) */
|
|
223
|
+
private mutex;
|
|
224
|
+
constructor(dataRoot: string);
|
|
225
|
+
/** 追加一条观察记录(内存 + JSONL 落盘 + 增量合并进状态档案) */
|
|
226
|
+
record(entry: BehaviorEntry): void;
|
|
227
|
+
/** 增量合并:entry → 内存 profile + 样本缓存(写盘由 flushProfile 完成) */
|
|
228
|
+
private mergeEntry;
|
|
229
|
+
/** 读状态档案(内存缓存优先;互斥锁内读文件) */
|
|
230
|
+
private loadProfile;
|
|
231
|
+
/** 读状态档案(公开;互斥锁内——预测查询与合并不并发冲突) */
|
|
232
|
+
readProfile(flowId: string): Promise<RegionProfile | undefined>;
|
|
233
|
+
/** 全部内存记录(供 L2 分析) */
|
|
234
|
+
all(): BehaviorEntry[];
|
|
235
|
+
/** 读取落盘的最近 N 条(跨 run 积累;供 L2 模式分析) */
|
|
236
|
+
readRecent(n: number): BehaviorEntry[];
|
|
237
|
+
/** 归档路径(供诊断/审计) */
|
|
238
|
+
path(): string;
|
|
239
|
+
/** 统计:按 区域/目标 分组的行为规律(L2 消费的聚合形态) */
|
|
240
|
+
summarize(): Array<{
|
|
241
|
+
stepId: string;
|
|
242
|
+
actionType: string;
|
|
243
|
+
selector: string;
|
|
244
|
+
count: number;
|
|
245
|
+
failRate: number;
|
|
246
|
+
avgDurationMs: number;
|
|
247
|
+
}>;
|
|
248
|
+
/**
|
|
249
|
+
* 增强层·预测性超时(docs/BEHAVIOR-SPACE-V2.md P0/P1):
|
|
250
|
+
* 用【状态档案】的历史耗时建议该步骤 verify 超时 = max(默认, avgDurationMs × 1.5)。
|
|
251
|
+
* 读 profile(增量维护,O(1) 读文件缓存,不再每次扫描 archive.jsonl)。
|
|
252
|
+
* 建议级:样本 < PREDICT_MIN_SAMPLES → 返回 0(档案不足,不增强,用默认);
|
|
253
|
+
* 无该步骤记录 → 返回 undefined(完全不增强)。
|
|
254
|
+
* 需传入 flowId(profile 按流程组织;v1 签名兼容由调用方补 flowId)。
|
|
255
|
+
*/
|
|
256
|
+
predictTimeout(flowId: string, stepId: string, actionType: string, defaultMs: number): Promise<number | undefined>;
|
|
257
|
+
/**
|
|
258
|
+
* 增强层·语义锚点(docs/BEHAVIOR-SPACE-V2.md P3):
|
|
259
|
+
* 读状态档案该步骤的命中元素指纹,生成替代选择器(选择器失效时的失败恢复备选)。
|
|
260
|
+
* 建议级(铁律1):count < ANCHOR_MIN_COUNT → 返回空数组(档案不足,不增强,走原错误);
|
|
261
|
+
* 无该步骤记录 → 返回空数组(完全不增强)。主流程不依赖(铁律2/3)。
|
|
262
|
+
*/
|
|
263
|
+
anchorSelectors(flowId: string, stepId: string, actionType: string): Promise<string[]>;
|
|
264
|
+
}
|
|
265
|
+
/** 预测性超时:最少样本数(机器安全门·门1 复用:≥3 才可信) */
|
|
266
|
+
export declare const PREDICT_MIN_SAMPLES = 3;
|
|
267
|
+
/** 预测性超时:历史均值安全系数(留余量,防波动) */
|
|
268
|
+
export declare const PREDICT_FACTOR = 1.5;
|
|
269
|
+
/** 行为档案的存档文件数(用于测试/诊断) */
|
|
270
|
+
export declare function archiveFileCount(dataRoot: string): number;
|
|
271
|
+
/** 行为档案目录总字节数(用于测试/诊断) */
|
|
272
|
+
export declare function archiveBytes(dataRoot: string): number;
|
package/dist/behavior.js
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { mkdirSync, appendFileSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { nowIso } from './storage.js';
|
|
4
|
+
import { writeFileAtomic, writeJsonAtomic } from './atomic.js';
|
|
5
|
+
/** 锚点指纹键(去重依据;tag 并入降低跨类型误并) */
|
|
6
|
+
export function anchorKey(fp) {
|
|
7
|
+
return [fp.tag ?? '', fp.text ?? '', fp.placeholder ?? '', fp.ariaLabel ?? '', fp.name ?? ''].join('|');
|
|
8
|
+
}
|
|
9
|
+
/** P3 锚点聚合上限(每 step|action 保留的锚点数;防无限增长) */
|
|
10
|
+
export const PROFILE_MAX_ANCHORS = 5;
|
|
11
|
+
/** 语义锚点:最少一致出现次数(机器安全门:≥2 才可信,替代人工确认) */
|
|
12
|
+
export const ANCHOR_MIN_COUNT = 2;
|
|
13
|
+
/** 每次动作最多尝试的锚点选择器数(保底降级链长度) */
|
|
14
|
+
export const ANCHOR_MAX_SELECTORS = 4;
|
|
15
|
+
/**
|
|
16
|
+
* P3 聚合锚点(纯函数,可单测):按指纹键去重,同键 count+1 并更新 lastAt(置前);
|
|
17
|
+
* 新键 count=1。超过上限丢最旧(数组尾部)。新增/更新在前(最近命中优先排序依据)。
|
|
18
|
+
*/
|
|
19
|
+
export function mergeAnchor(anchors, fp, at) {
|
|
20
|
+
const key = anchorKey(fp);
|
|
21
|
+
const existing = anchors.find((a) => anchorKey(a.fp) === key);
|
|
22
|
+
const rest = anchors.filter((a) => anchorKey(a.fp) !== key);
|
|
23
|
+
const merged = [
|
|
24
|
+
existing ? { fp: existing.fp, count: existing.count + 1, lastAt: at } : { fp, count: 1, lastAt: at },
|
|
25
|
+
...rest,
|
|
26
|
+
];
|
|
27
|
+
if (merged.length > PROFILE_MAX_ANCHORS)
|
|
28
|
+
merged.length = PROFILE_MAX_ANCHORS;
|
|
29
|
+
return merged;
|
|
30
|
+
}
|
|
31
|
+
/** CSS 属性值转义(属性选择器引号内安全) */
|
|
32
|
+
function cssEscapeAttr(v) {
|
|
33
|
+
return v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* P3 生成语义锚点选择器(纯函数,可单测):count ≥ ANCHOR_MIN_COUNT 的锚点,
|
|
37
|
+
* 按 count 降序生成 getBySels 兼容选择器(text: 精确文本 / placeholder / aria-label / name)。
|
|
38
|
+
* 返回空数组 = 档案不足(不增强,走原错误路径)。引擎零业务逻辑——只做定位框架。
|
|
39
|
+
*/
|
|
40
|
+
export function buildAnchorSelectors(anchors) {
|
|
41
|
+
if (!anchors)
|
|
42
|
+
return [];
|
|
43
|
+
const ranked = anchors
|
|
44
|
+
.filter((a) => a.count >= ANCHOR_MIN_COUNT)
|
|
45
|
+
.sort((a, b) => b.count - a.count);
|
|
46
|
+
const out = [];
|
|
47
|
+
for (const a of ranked) {
|
|
48
|
+
const fp = a.fp;
|
|
49
|
+
if (fp.text && fp.text.trim().length >= 2)
|
|
50
|
+
out.push(`text:${fp.text.trim()}`);
|
|
51
|
+
if (fp.placeholder)
|
|
52
|
+
out.push(`input[placeholder="${cssEscapeAttr(fp.placeholder)}"]`);
|
|
53
|
+
if (fp.ariaLabel)
|
|
54
|
+
out.push(`[aria-label="${cssEscapeAttr(fp.ariaLabel)}"]`);
|
|
55
|
+
if (fp.name)
|
|
56
|
+
out.push(`[name="${cssEscapeAttr(fp.name)}"]`);
|
|
57
|
+
if (out.length >= ANCHOR_MAX_SELECTORS)
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** 简易文本哈希(FNV-1a 32 位;仅用于变化检测,非加密) */
|
|
63
|
+
export function textHash(s) {
|
|
64
|
+
let h = 0x811c9dc5;
|
|
65
|
+
for (let i = 0; i < s.length; i++) {
|
|
66
|
+
h ^= s.charCodeAt(i);
|
|
67
|
+
h = Math.imul(h, 0x01000193);
|
|
68
|
+
}
|
|
69
|
+
return (h >>> 0).toString(16).padStart(8, '0');
|
|
70
|
+
}
|
|
71
|
+
/** 路由键(host+path,忽略 query/hash) */
|
|
72
|
+
export function routeKey(u) {
|
|
73
|
+
try {
|
|
74
|
+
const x = new URL(u);
|
|
75
|
+
return x.hostname + x.pathname;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return u;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* P2 规则匹配(纯函数,可单测):规则的全部 match 条件满足才命中。
|
|
83
|
+
* 引擎零业务逻辑——规则来自 behavior.rules.json,这里只执行匹配框架。
|
|
84
|
+
*/
|
|
85
|
+
export function matchRegionRule(rule, f) {
|
|
86
|
+
const m = rule.match;
|
|
87
|
+
if (m.textContains !== undefined && !f.text.includes(m.textContains))
|
|
88
|
+
return false;
|
|
89
|
+
if (m.textContainsAll !== undefined) {
|
|
90
|
+
for (const kw of m.textContainsAll) {
|
|
91
|
+
if (!f.text.includes(kw))
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (m.hasInput === true && !f.hasInput)
|
|
96
|
+
return false;
|
|
97
|
+
if (m.hasButton === true && !f.hasButton)
|
|
98
|
+
return false;
|
|
99
|
+
if (m.ancestorTag !== undefined && !f.tag.includes(m.ancestorTag))
|
|
100
|
+
return false;
|
|
101
|
+
if (m.ancestorClass !== undefined && !f.cls.includes(m.ancestorClass))
|
|
102
|
+
return false;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* P2 区域识别(纯函数,可单测):对每层祖先特征依次用规则匹配,命中即返回。
|
|
107
|
+
* 返回 { label, ruleId };无命中 → null。
|
|
108
|
+
*/
|
|
109
|
+
export function identifyRegionFromFeatures(rules, features) {
|
|
110
|
+
for (const f of features) {
|
|
111
|
+
for (const r of rules) {
|
|
112
|
+
if (matchRegionRule(r, f))
|
|
113
|
+
return { label: r.label, ruleId: r.id };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
/** 当前 profile schema 版本(升级时 bump + 迁移) */
|
|
119
|
+
export const PROFILE_SCHEMA_VERSION = 1;
|
|
120
|
+
/** 状态档案:每步骤保留的最大耗时样本数(防无限增长;超了丢最旧) */
|
|
121
|
+
export const PROFILE_MAX_SAMPLES = 50;
|
|
122
|
+
/** 百分位计算(sorted 数组) */
|
|
123
|
+
function percentile(sorted, p) {
|
|
124
|
+
if (sorted.length === 0)
|
|
125
|
+
return 0;
|
|
126
|
+
const idx = Math.min(sorted.length - 1, Math.max(0, Math.round((p / 100) * (sorted.length - 1))));
|
|
127
|
+
return sorted[idx];
|
|
128
|
+
}
|
|
129
|
+
/** 简易互斥锁(单进程内读-合并-写原子化;--http 多请求并发安全) */
|
|
130
|
+
export class Mutex {
|
|
131
|
+
tail = Promise.resolve();
|
|
132
|
+
async run(fn) {
|
|
133
|
+
const prev = this.tail;
|
|
134
|
+
let release;
|
|
135
|
+
this.tail = new Promise((r) => (release = r));
|
|
136
|
+
await prev;
|
|
137
|
+
try {
|
|
138
|
+
return await fn();
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
release();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 行为档案库:内存积累 + 落盘 JSONL(data/behavior/archive.jsonl,幂等追加)+ 状态档案
|
|
147
|
+
* (data/behavior/profiles/<flowId>.json,增量合并+原子写+互斥锁)。
|
|
148
|
+
* 单例由 app 层持有(与 RunStore 同级),run 期间通过 onBehavior 回调喂入。
|
|
149
|
+
*/
|
|
150
|
+
export class BehaviorArchive {
|
|
151
|
+
entries = [];
|
|
152
|
+
file;
|
|
153
|
+
profilesDir;
|
|
154
|
+
/** 状态档案内存缓存(flowId → profile);读-合并-写经互斥锁原子化 */
|
|
155
|
+
profileCache = new Map();
|
|
156
|
+
/** 每步骤耗时样本(内存:stepId|actionType → sorted 数组),用于 p50/p95 */
|
|
157
|
+
samplesCache = new Map();
|
|
158
|
+
/** 读-合并-写互斥锁(并发安全) */
|
|
159
|
+
mutex = new Mutex();
|
|
160
|
+
constructor(dataRoot) {
|
|
161
|
+
this.file = join(dataRoot, 'behavior', 'archive.jsonl');
|
|
162
|
+
this.profilesDir = join(dataRoot, 'behavior', 'profiles');
|
|
163
|
+
try {
|
|
164
|
+
mkdirSync(join(dataRoot, 'behavior'), { recursive: true });
|
|
165
|
+
mkdirSync(this.profilesDir, { recursive: true });
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// 目录不可写:旁路原则——构造不抛错,record 落盘时再静默失败
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** 追加一条观察记录(内存 + JSONL 落盘 + 增量合并进状态档案) */
|
|
172
|
+
record(entry) {
|
|
173
|
+
this.entries.push(entry);
|
|
174
|
+
try {
|
|
175
|
+
appendFileSync(this.file, JSON.stringify(entry) + '\n', 'utf8');
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// 落盘失败静默(观察层不阻断流程;旁路采集原则)
|
|
179
|
+
}
|
|
180
|
+
// 增量合并进状态档案(互斥锁内读-合并-写;失败静默)
|
|
181
|
+
void this.mutex.run(() => {
|
|
182
|
+
try {
|
|
183
|
+
this.mergeEntry(entry);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// profile 合并失败静默(旁路原则)
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/** 增量合并:entry → 内存 profile + 样本缓存(写盘由 flushProfile 完成) */
|
|
191
|
+
mergeEntry(entry) {
|
|
192
|
+
const { flowId, stepId, actionType } = entry;
|
|
193
|
+
// 样本缓存(p50/p95):只记 ok 的耗时
|
|
194
|
+
if (entry.result.ok) {
|
|
195
|
+
const key = `${stepId}|${actionType}`;
|
|
196
|
+
const arr = this.samplesCache.get(key) ?? [];
|
|
197
|
+
arr.push(entry.result.durationMs);
|
|
198
|
+
arr.sort((a, b) => a - b);
|
|
199
|
+
if (arr.length > PROFILE_MAX_SAMPLES)
|
|
200
|
+
arr.splice(0, arr.length - PROFILE_MAX_SAMPLES);
|
|
201
|
+
this.samplesCache.set(key, arr);
|
|
202
|
+
}
|
|
203
|
+
// profile 状态
|
|
204
|
+
let prof = this.profileCache.get(flowId);
|
|
205
|
+
if (!prof) {
|
|
206
|
+
prof = this.loadProfile(flowId) ?? { schemaVersion: PROFILE_SCHEMA_VERSION, flowId, updatedAt: nowIso(), steps: {} };
|
|
207
|
+
this.profileCache.set(flowId, prof);
|
|
208
|
+
}
|
|
209
|
+
const stepMap = prof.steps[stepId] ?? {};
|
|
210
|
+
const act = stepMap[actionType] ?? { seen: 0 };
|
|
211
|
+
act.seen += 1;
|
|
212
|
+
if (entry.result.ok) {
|
|
213
|
+
const key = `${stepId}|${actionType}`;
|
|
214
|
+
const samples = this.samplesCache.get(key) ?? [];
|
|
215
|
+
act.timing = {
|
|
216
|
+
samples: samples.length,
|
|
217
|
+
avgDurationMs: Math.round(samples.reduce((a, b) => a + b, 0) / samples.length),
|
|
218
|
+
p50Ms: percentile(samples, 50),
|
|
219
|
+
p95Ms: percentile(samples, 95),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// P3 语义锚点聚合:成功动作的命中元素指纹(去重累加 count;机器安全门数据源)
|
|
223
|
+
if (entry.result.ok && entry.hitEl) {
|
|
224
|
+
act.anchors = mergeAnchor(act.anchors ?? [], entry.hitEl, entry.at);
|
|
225
|
+
}
|
|
226
|
+
stepMap[actionType] = act;
|
|
227
|
+
prof.steps[stepId] = stepMap;
|
|
228
|
+
// P2 区域聚合:entry.region.label 出现计数(区域功能模型的置信度)
|
|
229
|
+
if (entry.region?.label) {
|
|
230
|
+
const regions = prof.regions ?? {};
|
|
231
|
+
const reg = regions[entry.region.label] ?? { seen: 0 };
|
|
232
|
+
reg.seen += 1;
|
|
233
|
+
if (entry.region.ruleId)
|
|
234
|
+
reg.ruleId = entry.region.ruleId;
|
|
235
|
+
regions[entry.region.label] = reg;
|
|
236
|
+
prof.regions = regions;
|
|
237
|
+
}
|
|
238
|
+
prof.updatedAt = nowIso();
|
|
239
|
+
// 原子写盘(互斥锁内,并发安全)
|
|
240
|
+
try {
|
|
241
|
+
writeJsonAtomic(join(this.profilesDir, `${flowId}.json`), prof);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// 写盘失败静默
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** 读状态档案(内存缓存优先;互斥锁内读文件) */
|
|
248
|
+
loadProfile(flowId) {
|
|
249
|
+
try {
|
|
250
|
+
const raw = readFileSync(join(this.profilesDir, `${flowId}.json`), 'utf8');
|
|
251
|
+
return JSON.parse(raw);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/** 读状态档案(公开;互斥锁内——预测查询与合并不并发冲突) */
|
|
258
|
+
async readProfile(flowId) {
|
|
259
|
+
return this.mutex.run(() => this.profileCache.get(flowId) ?? this.loadProfile(flowId));
|
|
260
|
+
}
|
|
261
|
+
/** 全部内存记录(供 L2 分析) */
|
|
262
|
+
all() {
|
|
263
|
+
return [...this.entries];
|
|
264
|
+
}
|
|
265
|
+
/** 读取落盘的最近 N 条(跨 run 积累;供 L2 模式分析) */
|
|
266
|
+
readRecent(n) {
|
|
267
|
+
try {
|
|
268
|
+
const raw = readFileSync(this.file, 'utf8');
|
|
269
|
+
const lines = raw.split('\n').filter(Boolean);
|
|
270
|
+
const out = [];
|
|
271
|
+
for (const l of lines.slice(-n)) {
|
|
272
|
+
try {
|
|
273
|
+
out.push(JSON.parse(l));
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
// 跳过坏行
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return [];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/** 归档路径(供诊断/审计) */
|
|
286
|
+
path() {
|
|
287
|
+
return this.file;
|
|
288
|
+
}
|
|
289
|
+
/** 统计:按 区域/目标 分组的行为规律(L2 消费的聚合形态) */
|
|
290
|
+
summarize() {
|
|
291
|
+
const byKey = new Map();
|
|
292
|
+
for (const e of this.entries) {
|
|
293
|
+
const k = `${e.stepId}|${e.actionType}|${e.selector}`;
|
|
294
|
+
const arr = byKey.get(k) ?? [];
|
|
295
|
+
arr.push(e);
|
|
296
|
+
byKey.set(k, arr);
|
|
297
|
+
}
|
|
298
|
+
const out = [];
|
|
299
|
+
for (const [k, arr] of byKey) {
|
|
300
|
+
const [stepId, actionType, selector] = k.split('|');
|
|
301
|
+
const fails = arr.filter((e) => !e.result.ok).length;
|
|
302
|
+
out.push({
|
|
303
|
+
stepId,
|
|
304
|
+
actionType,
|
|
305
|
+
selector,
|
|
306
|
+
count: arr.length,
|
|
307
|
+
failRate: fails / arr.length,
|
|
308
|
+
avgDurationMs: Math.round(arr.reduce((a, e) => a + e.result.durationMs, 0) / arr.length),
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return out;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* 增强层·预测性超时(docs/BEHAVIOR-SPACE-V2.md P0/P1):
|
|
315
|
+
* 用【状态档案】的历史耗时建议该步骤 verify 超时 = max(默认, avgDurationMs × 1.5)。
|
|
316
|
+
* 读 profile(增量维护,O(1) 读文件缓存,不再每次扫描 archive.jsonl)。
|
|
317
|
+
* 建议级:样本 < PREDICT_MIN_SAMPLES → 返回 0(档案不足,不增强,用默认);
|
|
318
|
+
* 无该步骤记录 → 返回 undefined(完全不增强)。
|
|
319
|
+
* 需传入 flowId(profile 按流程组织;v1 签名兼容由调用方补 flowId)。
|
|
320
|
+
*/
|
|
321
|
+
async predictTimeout(flowId, stepId, actionType, defaultMs) {
|
|
322
|
+
const prof = await this.mutex.run(() => this.profileCache.get(flowId) ?? this.loadProfile(flowId));
|
|
323
|
+
const act = prof?.steps[stepId]?.[actionType];
|
|
324
|
+
if (!act || !act.timing)
|
|
325
|
+
return undefined;
|
|
326
|
+
if (act.timing.samples < PREDICT_MIN_SAMPLES)
|
|
327
|
+
return 0;
|
|
328
|
+
const suggested = Math.max(defaultMs, Math.round(act.timing.avgDurationMs * PREDICT_FACTOR));
|
|
329
|
+
return suggested > defaultMs ? suggested : 0;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* 增强层·语义锚点(docs/BEHAVIOR-SPACE-V2.md P3):
|
|
333
|
+
* 读状态档案该步骤的命中元素指纹,生成替代选择器(选择器失效时的失败恢复备选)。
|
|
334
|
+
* 建议级(铁律1):count < ANCHOR_MIN_COUNT → 返回空数组(档案不足,不增强,走原错误);
|
|
335
|
+
* 无该步骤记录 → 返回空数组(完全不增强)。主流程不依赖(铁律2/3)。
|
|
336
|
+
*/
|
|
337
|
+
async anchorSelectors(flowId, stepId, actionType) {
|
|
338
|
+
const prof = await this.mutex.run(() => this.profileCache.get(flowId) ?? this.loadProfile(flowId));
|
|
339
|
+
return buildAnchorSelectors(prof?.steps[stepId]?.[actionType]?.anchors);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/** 预测性超时:最少样本数(机器安全门·门1 复用:≥3 才可信) */
|
|
343
|
+
export const PREDICT_MIN_SAMPLES = 3;
|
|
344
|
+
/** 预测性超时:历史均值安全系数(留余量,防波动) */
|
|
345
|
+
export const PREDICT_FACTOR = 1.5;
|
|
346
|
+
/** 行为档案的存档文件数(用于测试/诊断) */
|
|
347
|
+
export function archiveFileCount(dataRoot) {
|
|
348
|
+
const dir = join(dataRoot, 'behavior');
|
|
349
|
+
try {
|
|
350
|
+
return readdirSync(dir).filter((f) => f.endsWith('.jsonl')).length;
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/** 行为档案目录总字节数(用于测试/诊断) */
|
|
357
|
+
export function archiveBytes(dataRoot) {
|
|
358
|
+
const dir = join(dataRoot, 'behavior');
|
|
359
|
+
try {
|
|
360
|
+
const f = join(dir, 'archive.jsonl');
|
|
361
|
+
return statSync(f).size;
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return 0;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
//# sourceMappingURL=behavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavior.js","sourceRoot":"","sources":["../src/behavior.ts"],"names":[],"mappings":"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"}
|