skill-auto-loader-hook-paperfly777 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/README.md +142 -0
- package/index.ts +37 -4
- package/package.json +1 -1
- package/skill-router.config.json +1 -0
package/README.md
CHANGED
|
@@ -86,6 +86,148 @@ openclaw plugins install skill-auto-loader-hook-paperfly777
|
|
|
86
86
|
2. `skillsScanDirs` 如果写相对路径,也相对于插件目录解析。
|
|
87
87
|
3. `openclawConfigPath` 建议使用 `~/.openclaw/openclaw.json`。
|
|
88
88
|
|
|
89
|
+
## 使用说明(重点)
|
|
90
|
+
|
|
91
|
+
### 1) 怎么使用
|
|
92
|
+
|
|
93
|
+
1. 安装插件后,确保 `plugins.entries.skill-auto-loader-hook.enabled=true`。
|
|
94
|
+
2. 配置好 `routerConfigPath` 指向 `skill-router.config.json`。
|
|
95
|
+
3. 重启 gateway:`openclaw gateway restart`。
|
|
96
|
+
4. 之后每次用户发消息,插件会在 `before_prompt_build` 自动执行 skill 路由判断。
|
|
97
|
+
|
|
98
|
+
### 2) 配置文件在哪里
|
|
99
|
+
|
|
100
|
+
- OpenClaw 主配置:`~/.openclaw/openclaw.json`
|
|
101
|
+
- 插件路由配置:`skill-router.config.json`(默认按插件目录相对路径读取)
|
|
102
|
+
|
|
103
|
+
### 3) 自定义 Prompt 怎么配
|
|
104
|
+
|
|
105
|
+
在 `skill-router.config.json` 的每条 `rules[*].prompt` 里写即可,例如:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"id": "company-kb",
|
|
110
|
+
"keywords": ["知识库", "查文档", "公司规定"],
|
|
111
|
+
"preferSkills": ["company-knowledge-base"],
|
|
112
|
+
"excludeSkills": [],
|
|
113
|
+
"scopeNote": "仅限内部文档检索与制度问题",
|
|
114
|
+
"prompt": "先检索知识库再回答;若涉及删除/覆盖写入,必须二次确认。"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
推荐写法:
|
|
119
|
+
|
|
120
|
+
1. 先写使用范围(`scopeNote`)
|
|
121
|
+
2. 再写执行约束(`prompt`)
|
|
122
|
+
3. 避免只写关键词,不写动作规则
|
|
123
|
+
|
|
124
|
+
### 4) 白名单和黑名单怎么配
|
|
125
|
+
|
|
126
|
+
- 全局白名单:`includeSkills`
|
|
127
|
+
- 全局黑名单:`excludeSkills`
|
|
128
|
+
- 规则级白名单倾向:`rules[*].preferSkills`
|
|
129
|
+
- 规则级黑名单:`rules[*].excludeSkills`
|
|
130
|
+
|
|
131
|
+
示例:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"includeSkills": ["company-knowledge-base", "daily-report", "openclaw-feishu-plugin"],
|
|
136
|
+
"excludeSkills": ["remotion"],
|
|
137
|
+
"rules": [
|
|
138
|
+
{
|
|
139
|
+
"id": "daily-report",
|
|
140
|
+
"keywords": ["日报", "工时", "工作记录"],
|
|
141
|
+
"preferSkills": ["daily-report"],
|
|
142
|
+
"excludeSkills": ["company-knowledge-base"],
|
|
143
|
+
"prompt": "优先处理日报,不要误路由到知识库。"
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
说明:
|
|
150
|
+
|
|
151
|
+
1. `includeSkills` 不为空时,候选技能会先被限制在白名单内。
|
|
152
|
+
2. `excludeSkills` 会在全局层面直接排除。
|
|
153
|
+
3. 规则命中后会叠加 `preferSkills/excludeSkills` 做本轮精细路由。
|
|
154
|
+
|
|
155
|
+
## 参数说明(完整)
|
|
156
|
+
|
|
157
|
+
### A. `openclaw.json -> plugins.entries.skill-auto-loader-hook`
|
|
158
|
+
|
|
159
|
+
| 参数 | 类型 | 可选值/示例 | 默认值 | 作用 |
|
|
160
|
+
|---|---|---|---|---|
|
|
161
|
+
| `enabled` | boolean | `true/false` | `true` | 是否启用这个插件入口。 |
|
|
162
|
+
| `config.enabled` | boolean | `true/false` | `true` | 插件运行时开关。关闭后插件不做任何注入。 |
|
|
163
|
+
| `config.injectMode` | string | `prependContext` / `prependSystemContext` / `appendSystemContext` | `prependContext` | 选择把路由提示注入到哪里。 |
|
|
164
|
+
| `config.routerConfigPath` | string | `./skill-router.config.json` | `./skill-router.config.json` | 独立路由配置文件路径。相对路径按插件目录解析。 |
|
|
165
|
+
| `config.openclawConfigPath` | string | `~/.openclaw/openclaw.json` | `~/.openclaw/openclaw.json` | 读取默认模型信息的配置文件路径。 |
|
|
166
|
+
|
|
167
|
+
`injectMode` 选择建议:
|
|
168
|
+
|
|
169
|
+
1. `prependContext`:推荐。影响最小,兼容性最好。
|
|
170
|
+
2. `prependSystemContext`:约束最强,适合必须遵守路由的场景。
|
|
171
|
+
3. `appendSystemContext`:权重相对弱,适合补充说明。
|
|
172
|
+
|
|
173
|
+
`injectMode` 详细解释(这三个参数到底什么意思):
|
|
174
|
+
|
|
175
|
+
1. `prependContext`
|
|
176
|
+
- 含义:把插件生成的路由提示,放到“普通上下文”的前面。
|
|
177
|
+
- 特点:不会强压系统提示,兼容性最好,不容易和其他系统规则冲突。
|
|
178
|
+
- 适合:大多数场景,尤其是你只希望“引导模型优先用某些 skill”。
|
|
179
|
+
|
|
180
|
+
2. `prependSystemContext`
|
|
181
|
+
- 含义:把路由提示放到“系统上下文”最前面。
|
|
182
|
+
- 特点:约束力最强,模型更容易优先执行这段规则。
|
|
183
|
+
- 风险:如果规则写得太死,可能压过原有系统策略,导致回答风格变硬。
|
|
184
|
+
- 适合:强流程场景(例如必须先知识库检索、必须二次确认写操作)。
|
|
185
|
+
|
|
186
|
+
3. `appendSystemContext`
|
|
187
|
+
- 含义:把路由提示放到“系统上下文”末尾。
|
|
188
|
+
- 特点:仍在系统层,但通常权重低于前置系统上下文。
|
|
189
|
+
- 适合:你想补充一层路由提醒,但不想强覆盖原系统策略时使用。
|
|
190
|
+
|
|
191
|
+
### B. `skill-router.config.json` 顶层参数
|
|
192
|
+
|
|
193
|
+
| 参数 | 类型 | 可选值/示例 | 默认值 | 作用 |
|
|
194
|
+
|---|---|---|---|---|
|
|
195
|
+
| `enabled` | boolean | `true/false` | `true` | 路由配置总开关。 |
|
|
196
|
+
| `defaultBehavior` | string | `no-op` / `advisory` | `no-op` | 未命中规则时是否注入提示。 |
|
|
197
|
+
| `skillsScanDirs` | string[] | `["~/.openclaw/workspace/skills"]` | 自动推断目录 | 扫描已安装 skill 的目录列表。 |
|
|
198
|
+
| `includeSkills` | string[] | `["company-knowledge-base"]` | `[]` | 全局白名单。非空时仅这些 skill 参与候选。 |
|
|
199
|
+
| `excludeSkills` | string[] | `["remotion"]` | `[]` | 全局黑名单。始终排除这些 skill。 |
|
|
200
|
+
| `maxSkillsInPrompt` | number | `10` / `20` | `20` | 注入提示中最多携带多少个候选 skill。 |
|
|
201
|
+
| `defaultScopeNote` | string | `"仅限公司知识库场景"` | 空 | 规则缺少 `scopeNote` 时的默认范围说明。 |
|
|
202
|
+
| `rules` | array | 见下方规则参数 | `[]` | 场景路由规则集合。 |
|
|
203
|
+
|
|
204
|
+
`defaultBehavior` 选择建议:
|
|
205
|
+
|
|
206
|
+
1. `no-op`:推荐。未命中规则就不注入,避免“每轮追加”。
|
|
207
|
+
2. `advisory`:未命中也注入轻量提示,适合想保留弱引导的场景。
|
|
208
|
+
|
|
209
|
+
### C. `rules[*]` 规则参数
|
|
210
|
+
|
|
211
|
+
| 参数 | 类型 | 可选值/示例 | 是否必填 | 作用 |
|
|
212
|
+
|---|---|---|---|---|
|
|
213
|
+
| `id` | string | `"daily-report"` | 是 | 规则唯一标识,便于日志排障。 |
|
|
214
|
+
| `enabled` | boolean | `true/false` | 否 | 单条规则开关。 |
|
|
215
|
+
| `description` | string | `"日报相关路由"` | 否 | 规则说明文字。 |
|
|
216
|
+
| `keywords` | string[] | `["日报","工时"]` | 否 | 任意关键词命中即可。 |
|
|
217
|
+
| `allKeywords` | string[] | `["报销","流程"]` | 否 | 要求全部命中。 |
|
|
218
|
+
| `regexes` | string[] | `["(?i)日报.*提交"]` | 否 | 正则命中条件。 |
|
|
219
|
+
| `preferSkills` | string[] | `["daily-report"]` | 否 | 命中后优先的 skill。 |
|
|
220
|
+
| `excludeSkills` | string[] | `["company-knowledge-base"]` | 否 | 命中后排除的 skill。 |
|
|
221
|
+
| `scopeNote` | string | `"仅日报场景"` | 否 | 这条规则的适用范围说明。 |
|
|
222
|
+
| `prompt` | string | `"先确认草稿再上传"` | 否 | 规则级自定义提示词。 |
|
|
223
|
+
|
|
224
|
+
规则命中逻辑(重要):
|
|
225
|
+
|
|
226
|
+
1. `keywords`:满足“任意一个”即可。
|
|
227
|
+
2. `allKeywords`:要求“全部”出现。
|
|
228
|
+
3. `regexes`:任意一个正则匹配即可。
|
|
229
|
+
4. 三类条件会组合判断,最终命中后才进入 `preferSkills/excludeSkills` 处理。
|
|
230
|
+
|
|
89
231
|
### 1. `openclaw.json` 中的插件入口配置
|
|
90
232
|
|
|
91
233
|
```json
|
package/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { definePluginEntry } from "openclaw/plugin-sdk/core";
|
|
5
5
|
|
|
6
|
+
// 插件固定 ID:对应 openclaw.json 里的 plugins.entries.<id>
|
|
6
7
|
const PLUGIN_ID = "skill-auto-loader-hook";
|
|
7
8
|
|
|
8
9
|
type RoutingRule = {
|
|
@@ -20,6 +21,7 @@ type RoutingRule = {
|
|
|
20
21
|
|
|
21
22
|
type RouterFileConfig = {
|
|
22
23
|
enabled?: boolean;
|
|
24
|
+
defaultBehavior?: "no-op" | "advisory";
|
|
23
25
|
skillsScanDirs?: string[];
|
|
24
26
|
includeSkills?: string[];
|
|
25
27
|
excludeSkills?: string[];
|
|
@@ -41,10 +43,12 @@ type SkillMeta = {
|
|
|
41
43
|
skillPath: string;
|
|
42
44
|
};
|
|
43
45
|
|
|
46
|
+
// 工具函数:把任意输入安全转换为字符串
|
|
44
47
|
function safeString(value: unknown): string {
|
|
45
48
|
return typeof value === "string" ? value : "";
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
// 工具函数:把 "~/" 展开为用户 home 目录绝对路径
|
|
48
52
|
function expandHome(inputPath: string): string {
|
|
49
53
|
if (!inputPath) {
|
|
50
54
|
return inputPath;
|
|
@@ -55,6 +59,7 @@ function expandHome(inputPath: string): string {
|
|
|
55
59
|
return inputPath;
|
|
56
60
|
}
|
|
57
61
|
|
|
62
|
+
// 工具函数:把相对路径解析为基于 baseDir 的绝对路径
|
|
58
63
|
function resolvePath(inputPath: string, baseDir: string): string {
|
|
59
64
|
const expanded = expandHome(inputPath);
|
|
60
65
|
if (!expanded) {
|
|
@@ -66,6 +71,7 @@ function resolvePath(inputPath: string, baseDir: string): string {
|
|
|
66
71
|
return path.resolve(baseDir, expanded);
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
// 安全读取 JSON:文件不存在或格式错误时返回 null,不抛异常
|
|
69
75
|
function readJsonFile(filePath: string): any {
|
|
70
76
|
try {
|
|
71
77
|
const raw = fs.readFileSync(filePath, "utf8");
|
|
@@ -75,6 +81,7 @@ function readJsonFile(filePath: string): any {
|
|
|
75
81
|
}
|
|
76
82
|
}
|
|
77
83
|
|
|
84
|
+
// 从 OpenClaw 消息 content 结构中抽取纯文本
|
|
78
85
|
function extractTextFromContent(content: unknown): string {
|
|
79
86
|
if (typeof content === "string") {
|
|
80
87
|
return content;
|
|
@@ -102,6 +109,7 @@ function extractTextFromContent(content: unknown): string {
|
|
|
102
109
|
return "";
|
|
103
110
|
}
|
|
104
111
|
|
|
112
|
+
// 提取“最后一条用户消息”作为本轮路由判断输入
|
|
105
113
|
function extractLatestUserText(event: unknown): string {
|
|
106
114
|
if (!event || typeof event !== "object") {
|
|
107
115
|
return "";
|
|
@@ -128,6 +136,7 @@ function extractLatestUserText(event: unknown): string {
|
|
|
128
136
|
return fallbackPrompt.trim();
|
|
129
137
|
}
|
|
130
138
|
|
|
139
|
+
// 从 openclaw.json 读取插件级配置(plugins.entries.<id>.config)
|
|
131
140
|
function normalizePluginConfig(api: any): PluginConfig {
|
|
132
141
|
const pluginCfg =
|
|
133
142
|
api?.config?.plugins?.entries?.[PLUGIN_ID]?.config ??
|
|
@@ -146,6 +155,7 @@ function normalizePluginConfig(api: any): PluginConfig {
|
|
|
146
155
|
};
|
|
147
156
|
}
|
|
148
157
|
|
|
158
|
+
// 从独立配置文件读取路由规则(skill-router.config.json)
|
|
149
159
|
function readRouterConfig(configPath: string, baseDir: string): RouterFileConfig {
|
|
150
160
|
const config = readJsonFile(resolvePath(configPath, baseDir));
|
|
151
161
|
if (!config || typeof config !== "object") {
|
|
@@ -154,6 +164,7 @@ function readRouterConfig(configPath: string, baseDir: string): RouterFileConfig
|
|
|
154
164
|
return config as RouterFileConfig;
|
|
155
165
|
}
|
|
156
166
|
|
|
167
|
+
// 从 openclaw.json 读取默认模型信息,用于注入上下文
|
|
157
168
|
function getDefaultModelInfo(openclawConfigPath: string): string {
|
|
158
169
|
const cfg = readJsonFile(expandHome(openclawConfigPath));
|
|
159
170
|
if (!cfg || typeof cfg !== "object") {
|
|
@@ -173,6 +184,7 @@ function getDefaultModelInfo(openclawConfigPath: string): string {
|
|
|
173
184
|
return "openclaw.json 中未显式配置默认模型";
|
|
174
185
|
}
|
|
175
186
|
|
|
187
|
+
// 解析 SKILL.md 头部 frontmatter(name/description)
|
|
176
188
|
function parseYamlLikeFrontmatter(raw: string): { name: string; description: string } {
|
|
177
189
|
const result = { name: "", description: "" };
|
|
178
190
|
if (!raw.startsWith("---")) {
|
|
@@ -216,6 +228,7 @@ function parseYamlLikeFrontmatter(raw: string): { name: string; description: str
|
|
|
216
228
|
return result;
|
|
217
229
|
}
|
|
218
230
|
|
|
231
|
+
// frontmatter 缺失时,退化为读取 markdown 一级标题作为名称
|
|
219
232
|
function extractHeadingFallback(raw: string): string {
|
|
220
233
|
const lines = raw.split(/\r?\n/);
|
|
221
234
|
for (const line of lines) {
|
|
@@ -226,6 +239,7 @@ function extractHeadingFallback(raw: string): string {
|
|
|
226
239
|
return "";
|
|
227
240
|
}
|
|
228
241
|
|
|
242
|
+
// 从一个 skill 目录提取技能元信息
|
|
229
243
|
function extractSkillMeta(skillDir: string): SkillMeta | null {
|
|
230
244
|
const skillMdPath = path.join(skillDir, "SKILL.md");
|
|
231
245
|
if (!fs.existsSync(skillMdPath)) {
|
|
@@ -244,6 +258,7 @@ function extractSkillMeta(skillDir: string): SkillMeta | null {
|
|
|
244
258
|
};
|
|
245
259
|
}
|
|
246
260
|
|
|
261
|
+
// 扫描配置的技能目录,收集“已安装 skill”列表
|
|
247
262
|
function scanInstalledSkills(scanDirs: string[]): SkillMeta[] {
|
|
248
263
|
const results: SkillMeta[] = [];
|
|
249
264
|
const visited = new Set<string>();
|
|
@@ -274,6 +289,7 @@ function scanInstalledSkills(scanDirs: string[]): SkillMeta[] {
|
|
|
274
289
|
return results.sort((a, b) => a.name.localeCompare(b.name));
|
|
275
290
|
}
|
|
276
291
|
|
|
292
|
+
// 规则匹配器:支持 keywords / allKeywords / regexes
|
|
277
293
|
function matchesRule(text: string, rule: RoutingRule): boolean {
|
|
278
294
|
const normalized = text.toLowerCase();
|
|
279
295
|
const keywords = Array.isArray(rule.keywords) ? rule.keywords : [];
|
|
@@ -302,6 +318,7 @@ function matchesRule(text: string, rule: RoutingRule): boolean {
|
|
|
302
318
|
return hasMatcher && anyKeywordMatched && allKeywordMatched && regexMatched;
|
|
303
319
|
}
|
|
304
320
|
|
|
321
|
+
// 先应用全局白名单/黑名单,再应用规则级偏好与排除
|
|
305
322
|
function applyRuleFiltering(skills: SkillMeta[], routerCfg: RouterFileConfig, matchedRules: RoutingRule[]): SkillMeta[] {
|
|
306
323
|
let filtered = [...skills];
|
|
307
324
|
|
|
@@ -334,15 +351,15 @@ function applyRuleFiltering(skills: SkillMeta[], routerCfg: RouterFileConfig, ma
|
|
|
334
351
|
return filtered.slice(0, maxSkills);
|
|
335
352
|
}
|
|
336
353
|
|
|
354
|
+
// 生成精简版技能列表,避免注入内容过长
|
|
337
355
|
function renderSkillList(skills: SkillMeta[]): string {
|
|
338
356
|
if (skills.length === 0) {
|
|
339
357
|
return "当前未扫描到可用 skill。";
|
|
340
358
|
}
|
|
341
|
-
return skills
|
|
342
|
-
.map((skill, index) => `${index + 1}. ${skill.name}\n说明:${skill.description}\n路径:${skill.skillPath}`)
|
|
343
|
-
.join("\n\n");
|
|
359
|
+
return skills.map((skill, index) => `${index + 1}. ${skill.name}(${skill.description.slice(0, 80)})`).join("\n");
|
|
344
360
|
}
|
|
345
361
|
|
|
362
|
+
// 渲染命中规则说明,供模型做本轮技能路由判断
|
|
346
363
|
function renderRuleHints(matchedRules: RoutingRule[], routerCfg: RouterFileConfig): string {
|
|
347
364
|
if (matchedRules.length === 0) {
|
|
348
365
|
return routerCfg.defaultScopeNote ? `默认范围提示:${routerCfg.defaultScopeNote}` : "未命中任何自定义规则。";
|
|
@@ -372,6 +389,7 @@ function renderRuleHints(matchedRules: RoutingRule[], routerCfg: RouterFileConfi
|
|
|
372
389
|
.join("\n\n");
|
|
373
390
|
}
|
|
374
391
|
|
|
392
|
+
// 构造最终注入 payload(用于 before_prompt_build)
|
|
375
393
|
function buildRoutingPrompt(
|
|
376
394
|
userText: string,
|
|
377
395
|
defaultModel: string,
|
|
@@ -386,7 +404,7 @@ function buildRoutingPrompt(
|
|
|
386
404
|
lines.push("");
|
|
387
405
|
lines.push("请结合以下信息判断本轮是否需要优先使用某个 skill。");
|
|
388
406
|
lines.push("");
|
|
389
|
-
lines.push("
|
|
407
|
+
lines.push("一、候选 skill(已过滤)");
|
|
390
408
|
lines.push(renderSkillList(scannedSkills));
|
|
391
409
|
lines.push("");
|
|
392
410
|
lines.push("二、本轮命中的自定义规则");
|
|
@@ -413,6 +431,7 @@ export default definePluginEntry({
|
|
|
413
431
|
api.on(
|
|
414
432
|
"before_prompt_build",
|
|
415
433
|
(event: unknown) => {
|
|
434
|
+
// 步骤 1:读取插件配置与独立路由配置
|
|
416
435
|
const cfg = normalizePluginConfig(api);
|
|
417
436
|
if (!cfg.enabled) {
|
|
418
437
|
return undefined;
|
|
@@ -423,11 +442,13 @@ export default definePluginEntry({
|
|
|
423
442
|
return undefined;
|
|
424
443
|
}
|
|
425
444
|
|
|
445
|
+
// 步骤 2:提取本轮用户输入
|
|
426
446
|
const userText = extractLatestUserText(event);
|
|
427
447
|
if (!userText) {
|
|
428
448
|
return undefined;
|
|
429
449
|
}
|
|
430
450
|
|
|
451
|
+
// 步骤 3:扫描并收集可用 skill
|
|
431
452
|
const scanDirs =
|
|
432
453
|
Array.isArray(routerCfg.skillsScanDirs) && routerCfg.skillsScanDirs.length > 0
|
|
433
454
|
? routerCfg.skillsScanDirs.map((dir) => resolvePath(dir, __dirname))
|
|
@@ -435,6 +456,12 @@ export default definePluginEntry({
|
|
|
435
456
|
|
|
436
457
|
const allSkills = scanInstalledSkills(scanDirs);
|
|
437
458
|
const matchedRules = (routerCfg.rules || []).filter((rule) => rule.enabled !== false && matchesRule(userText, rule));
|
|
459
|
+
const defaultBehavior = routerCfg.defaultBehavior || "no-op";
|
|
460
|
+
// 步骤 4:默认 no-op 时,未命中规则就不注入(避免每轮追加)
|
|
461
|
+
if (matchedRules.length === 0 && defaultBehavior === "no-op") {
|
|
462
|
+
return undefined;
|
|
463
|
+
}
|
|
464
|
+
// 步骤 5:过滤候选 skill,并构造注入内容
|
|
438
465
|
const candidateSkills = applyRuleFiltering(allSkills, routerCfg, matchedRules);
|
|
439
466
|
const defaultModel = getDefaultModelInfo(cfg.openclawConfigPath!);
|
|
440
467
|
const payload = buildRoutingPrompt(userText, defaultModel, candidateSkills, matchedRules, routerCfg);
|
|
@@ -443,12 +470,18 @@ export default definePluginEntry({
|
|
|
443
470
|
`skill-auto-loader-hook: before_prompt_build matchedRules=${matchedRules.length} candidateSkills=${candidateSkills.length}`,
|
|
444
471
|
);
|
|
445
472
|
|
|
473
|
+
// injectMode = prependSystemContext:
|
|
474
|
+
// 注入到系统上下文最前面,约束最强,优先级通常最高。
|
|
446
475
|
if (cfg.injectMode === "prependSystemContext") {
|
|
447
476
|
return { prependSystemContext: payload };
|
|
448
477
|
}
|
|
478
|
+
// injectMode = appendSystemContext:
|
|
479
|
+
// 注入到系统上下文末尾,仍属于系统层,但权重通常弱于前置系统上下文。
|
|
449
480
|
if (cfg.injectMode === "appendSystemContext") {
|
|
450
481
|
return { appendSystemContext: payload };
|
|
451
482
|
}
|
|
483
|
+
// injectMode = prependContext(默认):
|
|
484
|
+
// 注入到普通上下文前部,影响适中,兼容性最好,推荐默认使用。
|
|
452
485
|
return { prependContext: payload };
|
|
453
486
|
},
|
|
454
487
|
{ priority: 50 },
|
package/package.json
CHANGED