@chaoset/adaptive-perf 0.3.1 → 0.4.0
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 +32 -0
- package/client/client.cjs +35 -2
- package/lib/index.mjs +155 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,17 @@
|
|
|
20
20
|
- **运行时上下文抑制**:对目标 preset 的会话调用 `suppressRuntimeContext()`
|
|
21
21
|
(与极简模式的 `includeRuntimeContext: false` 同一机制),每次模型请求省掉
|
|
22
22
|
"Current runtime context" 快照文本,**零功能损失**。
|
|
23
|
+
- **极简提示词层(minimalPrompt)**:参考实现的完整锚定条件——首轮轨迹由
|
|
24
|
+
**Minimal 的完整 system prompt** 决定,只收窄工具 schema 不够(标准/PTC 的
|
|
25
|
+
系统提示仍带 `harness:identity` / `harness:source` / `app:web-surface` 三个
|
|
26
|
+
全局引导段与标准 persona,思维链仍是 standard-like 的 "Let me…" 叙述)。本层
|
|
27
|
+
对目标会话:
|
|
28
|
+
- 按名阴影屏蔽三个全局引导段(空段在装配时被丢弃,等同极简 `complete`
|
|
29
|
+
persona 的效果;plan-mode 与 PTC 的 SDK 段不受影响);
|
|
30
|
+
- 按名阴影替换 `deployment:persona` 为极简语域 persona(默认与极简模式
|
|
31
|
+
逐字相同:`You are a helpful software engineer assistant.`)。
|
|
32
|
+
两处均为 agent 作用域的 prompt 段阴影,仅影响目标会话;**对已恢复/已晋升的
|
|
33
|
+
旧会话同样生效**(不依赖 bootstrap 阶段)。
|
|
23
34
|
- **工具目录自适应精简**:会话启动时按"工具族"默认隐藏高开销低频工具
|
|
24
35
|
(子代理 / 工作流 / ralph / goal 等编排类),只保留核心编码工具
|
|
25
36
|
(bash / 文件读写编辑 / 检索 / jobs / todo / 提问 / 网页搜索 / 技能 / 计划)。
|
|
@@ -36,6 +47,7 @@
|
|
|
36
47
|
|---|---|---|---|
|
|
37
48
|
| 首轮轨迹(决定后续行为风格) | Minimal 工具对锚定(5/5) | 任何 standard 系 schema 落入 standard-like(11/11) | 请求 #1 收窄到真实 Minimal 工具对,首个持久信号后恢复 |
|
|
38
49
|
| 首轮注入提醒 | 无 skill 目录/AGENTS.md 注入 | 自动注入(在场时锚定 0/9) | 请求 #1 剥离 `skill-catalog` + `agent-instructions` |
|
|
50
|
+
| 系统提示语域(persona + 全局引导段) | 一句话 persona,无任何引导段 | identity/source/web-surface 引导段 + 标准 persona("Let me…" 叙述来源) | minimalPrompt 层按名阴影屏蔽 3 个全局段 + 替换极简 persona(对旧会话同样生效) |
|
|
39
51
|
| 运行时上下文快照 | 关闭(`includeRuntimeContext: false`) | 每次请求注入文件策略/审批策略等快照 | 同一机制:`suppressRuntimeContext()` |
|
|
40
52
|
| 模型可见工具目录 | 2 个(bash、str_replace_editor) | ~22 个工具 schema 全部进请求 | bootstrap 后默认隐藏 4 个编排类工具族(~11 个工具),按需放行 |
|
|
41
53
|
| PTC SDK 参考段 | 无 | 全部工具的类型+描述渲染进提示 | 随目录缩小(同一 `visible` 视图驱动) |
|
|
@@ -89,6 +101,26 @@ dsh plugin --profile web remove @chaoset/adaptive-perf
|
|
|
89
101
|
| `escalateOnUnknownTool` | `true` | 工具调用失败(UNKNOWN_TOOL)→ 放行该族 |
|
|
90
102
|
| `coreTools` | 核心编码工具 | 展示用:不进入任何限制族 |
|
|
91
103
|
| `families` | 见下 | 工具族:`{ 族名: { enabled, tools, keywords } }` |
|
|
104
|
+
| `bootstrap` | 见下 | 首轮锚定(工具对 / 晋升信号 / 剥离上下文 / 压缩恢复集 / 预算封顶) |
|
|
105
|
+
| `minimalPrompt` | 见下 | 极简提示词层(语域锚定) |
|
|
106
|
+
|
|
107
|
+
`minimalPrompt`(极简提示词层,0.4.0 新增):
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"enabled": true,
|
|
112
|
+
"persona": "You are a helpful software engineer assistant.",
|
|
113
|
+
"suppressSections": true
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- `persona`:按名阴影替换 `deployment:persona`;默认与极简模式逐字相同,留空
|
|
118
|
+
(`""`)则不替换。
|
|
119
|
+
- `suppressSections`:屏蔽 `harness:identity` / `harness:source` / `app:web-surface`
|
|
120
|
+
三个全局引导段(等同极简 `complete` persona 的效果;plan-mode 与 PTC 的
|
|
121
|
+
SDK 段不受影响)。
|
|
122
|
+
- 生效范围:目标 preset 的全部会话,**包括已恢复/已晋升的旧会话**(不依赖
|
|
123
|
+
bootstrap 阶段);配置保存后热生效。
|
|
92
124
|
|
|
93
125
|
默认工具族(可整族禁用、改名、增删触发词):
|
|
94
126
|
|
package/client/client.cjs
CHANGED
|
@@ -55,7 +55,13 @@ window.__ModuleLoader__.load({
|
|
|
55
55
|
bootstrapCompactionTools: "压缩后工作集",
|
|
56
56
|
fieldBootstrapCompactionTools: "compaction/end 之后、再次晋升前额外可用的工具(核心工作集)。逗号分隔。",
|
|
57
57
|
bootstrapMaxTokens: "首轮输出预算封顶(token)",
|
|
58
|
-
fieldBootstrapMaxTokens: "请求 #1 的 maxTokens 封顶,晋升后自动剥离;0 = 不封顶(opt-in)"
|
|
58
|
+
fieldBootstrapMaxTokens: "请求 #1 的 maxTokens 封顶,晋升后自动剥离;0 = 不封顶(opt-in)",
|
|
59
|
+
minimalPromptEnabled: "极简提示词层(语域锚定)",
|
|
60
|
+
fieldMinimalPromptEnabled: "把系统提示拉回极简语域:屏蔽全局引导段 + 替换 persona。参考实现的完整锚定条件——仅收窄工具不足以翻转思维链风格(let me → let's/i'll/i need)",
|
|
61
|
+
minimalPromptPersona: "persona 文本",
|
|
62
|
+
fieldMinimalPromptPersona: "按名替换 deployment:persona;默认与极简模式逐字相同。留空 = 不替换(保留原 persona)",
|
|
63
|
+
minimalPromptSuppressSections: "屏蔽全局引导段",
|
|
64
|
+
fieldMinimalPromptSuppressSections: "屏蔽 harness:identity / harness:source / app:web-surface 三个全局段(等同极简 complete persona 的效果;plan-mode 与 PTC 的 SDK 段不受影响)"
|
|
59
65
|
};
|
|
60
66
|
const en = {
|
|
61
67
|
title: "Adaptive performance (adaptive-perf)",
|
|
@@ -94,7 +100,13 @@ window.__ModuleLoader__.load({
|
|
|
94
100
|
bootstrapCompactionTools: "Post-compaction work set",
|
|
95
101
|
fieldBootstrapCompactionTools: "Extra tools available after compaction/end until a new promotion signal (core work set). Comma-separated.",
|
|
96
102
|
bootstrapMaxTokens: "First-request output cap (tokens)",
|
|
97
|
-
fieldBootstrapMaxTokens: "maxTokens cap for request #1, stripped after promotion; 0 = no cap (opt-in)"
|
|
103
|
+
fieldBootstrapMaxTokens: "maxTokens cap for request #1, stripped after promotion; 0 = no cap (opt-in)",
|
|
104
|
+
minimalPromptEnabled: "Minimal prompt layer (register anchor)",
|
|
105
|
+
fieldMinimalPromptEnabled: "Pull the system prompt back to the minimal register: suppress the global orientation sections and replace the persona. The reference's full anchoring condition — tool narrowing alone does not flip the thinking style (let me → let's/i'll/i need)",
|
|
106
|
+
minimalPromptPersona: "Persona text",
|
|
107
|
+
fieldMinimalPromptPersona: "Shadows deployment:persona by name; defaults to the exact minimal-mode text. Empty = keep the original persona",
|
|
108
|
+
minimalPromptSuppressSections: "Suppress global orientation sections",
|
|
109
|
+
fieldMinimalPromptSuppressSections: "Shadow harness:identity / harness:source / app:web-surface to empty (same effect as minimal's complete persona; plan-mode and the PTC SDK sections are unaffected)"
|
|
98
110
|
};
|
|
99
111
|
|
|
100
112
|
// ── 表单字段 ─────────────────────────────────────────────────────────
|
|
@@ -317,6 +329,27 @@ window.__ModuleLoader__.load({
|
|
|
317
329
|
setDraft({ ...draft, bootstrap: { ...(draft.bootstrap || {}), maxTokens: Number.isSafeInteger(n) && n > 0 ? n : 0 } });
|
|
318
330
|
}
|
|
319
331
|
}),
|
|
332
|
+
react.createElement(BoolField, {
|
|
333
|
+
label: t("minimalPromptEnabled"),
|
|
334
|
+
hint: t("fieldMinimalPromptEnabled"),
|
|
335
|
+
value: draft === null ? false : (draft.minimalPrompt && draft.minimalPrompt.enabled === true),
|
|
336
|
+
disabled: draft === null,
|
|
337
|
+
onChange: (v) => setDraft({ ...draft, minimalPrompt: { ...(draft.minimalPrompt || {}), enabled: v } })
|
|
338
|
+
}),
|
|
339
|
+
react.createElement(BoolField, {
|
|
340
|
+
label: t("minimalPromptSuppressSections"),
|
|
341
|
+
hint: t("fieldMinimalPromptSuppressSections"),
|
|
342
|
+
value: draft === null ? false : (draft.minimalPrompt && draft.minimalPrompt.suppressSections === true),
|
|
343
|
+
disabled: draft === null || (draft.minimalPrompt && draft.minimalPrompt.enabled === false),
|
|
344
|
+
onChange: (v) => setDraft({ ...draft, minimalPrompt: { ...(draft.minimalPrompt || {}), suppressSections: v } })
|
|
345
|
+
}),
|
|
346
|
+
react.createElement(TextField, {
|
|
347
|
+
label: t("minimalPromptPersona"),
|
|
348
|
+
hint: t("fieldMinimalPromptPersona"),
|
|
349
|
+
value: draft === null ? "" : ((draft.minimalPrompt && draft.minimalPrompt.persona) || ""),
|
|
350
|
+
disabled: draft === null || (draft.minimalPrompt && draft.minimalPrompt.enabled === false),
|
|
351
|
+
onChange: (v) => setDraft({ ...draft, minimalPrompt: { ...(draft.minimalPrompt || {}), persona: v } })
|
|
352
|
+
}),
|
|
320
353
|
react.createElement(Field, {
|
|
321
354
|
label: t("families"),
|
|
322
355
|
hint: familiesInvalid ? t("invalidFamilies") + (familiesError !== null ? " — " + familiesError : "") : t("fieldFamilies")
|
package/lib/index.mjs
CHANGED
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
* - agent.ctx.systemPrompt.suppressRuntimeContext() 抑制上下文快照
|
|
43
43
|
* - agent.ctx.tools.schemas(agent) 读取该 agent 当前可见工具(限制交集)
|
|
44
44
|
* - agent.ctx.tools.restrict({ deny }) 按 agent 作用域裁剪继承工具
|
|
45
|
-
* - system-prompt/assemble(waterfall)
|
|
45
|
+
* - system-prompt/assemble(waterfall) 请求装配(早期实现;bootstrap 目录
|
|
46
|
+
* 收窄改用 tools.restrict——PTC 模式下 assembly.tools 只有 run_code,
|
|
47
|
+
* 过滤会降级失效,而 restrict 同时驱动 API 目录与 PTC SDK 参考段)
|
|
46
48
|
* - agent/pre-step(waterfall) 剥离自动注入的上下文消息(source.kind)
|
|
47
49
|
* - agent/request(waterfall) 首轮输出预算封顶
|
|
48
50
|
* - session/event 增量喂入持久事件(晋升 / compaction 纪元)
|
|
@@ -141,6 +143,27 @@ export const DEFAULT_CONFIG = {
|
|
|
141
143
|
/** 请求 #1 的输出预算封顶(token);0 = 不封顶(opt-in)。 */
|
|
142
144
|
maxTokens: 0,
|
|
143
145
|
},
|
|
146
|
+
/**
|
|
147
|
+
* 极简提示词层(语域锚定,参照 dsh-anchored-standard 的完整条件)。
|
|
148
|
+
*
|
|
149
|
+
* 参考实现指出:首轮"轨迹"(思维链风格)锚定需要 **Minimal 的完整 system
|
|
150
|
+
* prompt**——只收窄工具 schema 不够。本层对目标 preset 的会话:
|
|
151
|
+
* - suppressSections:按名阴影屏蔽全局引导段(harness:identity、
|
|
152
|
+
* harness:source、app:web-surface),空段在装配时被丢弃,等同极简
|
|
153
|
+
* complete persona 的效果(plan-mode 段、PTC 的 SDK 段不受影响);
|
|
154
|
+
* - persona:按名阴影替换 deployment:persona 为极简语域的短 persona
|
|
155
|
+
* (默认与极简模式逐字相同;留空则不替换)。
|
|
156
|
+
* 两处都是 agent 作用域的 prompt 段阴影,仅影响目标会话,随会话销毁自动
|
|
157
|
+
* 释放;对已恢复/已晋升的旧会话同样生效(不依赖 bootstrap 阶段)。
|
|
158
|
+
*/
|
|
159
|
+
minimalPrompt: {
|
|
160
|
+
/** 是否启用极简提示词层。 */
|
|
161
|
+
enabled: true,
|
|
162
|
+
/** 替换后的 persona 文本;与极简模式相同可完全对齐语域。留空不替换。 */
|
|
163
|
+
persona: 'You are a helpful software engineer assistant.',
|
|
164
|
+
/** 屏蔽全局引导段(identity / source / web-surface)。 */
|
|
165
|
+
suppressSections: true,
|
|
166
|
+
},
|
|
144
167
|
};
|
|
145
168
|
|
|
146
169
|
/** 轻量配置校验/归一化:非法字段回退默认值,避免 config.json 或 remote.set
|
|
@@ -201,6 +224,15 @@ export function normalizeConfig(source, defaults = DEFAULT_CONFIG) {
|
|
|
201
224
|
compactionTools: stringListOrEmpty(rawBootstrap.compactionTools, db.compactionTools),
|
|
202
225
|
maxTokens,
|
|
203
226
|
};
|
|
227
|
+
const rawMP = raw.minimalPrompt !== null && typeof raw.minimalPrompt === 'object' && !Array.isArray(raw.minimalPrompt)
|
|
228
|
+
? raw.minimalPrompt
|
|
229
|
+
: defaults.minimalPrompt;
|
|
230
|
+
const dm = defaults.minimalPrompt;
|
|
231
|
+
const minimalPrompt = {
|
|
232
|
+
enabled: boolValue(rawMP.enabled, dm.enabled),
|
|
233
|
+
persona: typeof rawMP.persona === 'string' ? rawMP.persona.trim() : dm.persona,
|
|
234
|
+
suppressSections: boolValue(rawMP.suppressSections, dm.suppressSections),
|
|
235
|
+
};
|
|
204
236
|
return {
|
|
205
237
|
enabled: boolValue(merged.enabled, defaults.enabled),
|
|
206
238
|
presets: stringList(merged.presets, defaults.presets),
|
|
@@ -211,6 +243,7 @@ export function normalizeConfig(source, defaults = DEFAULT_CONFIG) {
|
|
|
211
243
|
coreTools: stringList(merged.coreTools, defaults.coreTools),
|
|
212
244
|
families,
|
|
213
245
|
bootstrap,
|
|
246
|
+
minimalPrompt,
|
|
214
247
|
};
|
|
215
248
|
}
|
|
216
249
|
|
|
@@ -268,10 +301,37 @@ export function validateConfig(partial) {
|
|
|
268
301
|
}
|
|
269
302
|
}
|
|
270
303
|
}
|
|
304
|
+
if (partial.minimalPrompt !== void 0) {
|
|
305
|
+
const m = partial.minimalPrompt;
|
|
306
|
+
if (m === null || typeof m !== 'object' || Array.isArray(m)) {
|
|
307
|
+
throw new TypeError('adaptive-perf config field "minimalPrompt" must be an object');
|
|
308
|
+
}
|
|
309
|
+
if (m.enabled !== void 0 && typeof m.enabled !== 'boolean') {
|
|
310
|
+
throw new TypeError('adaptive-perf config field "minimalPrompt.enabled" must be a boolean');
|
|
311
|
+
}
|
|
312
|
+
if (m.suppressSections !== void 0 && typeof m.suppressSections !== 'boolean') {
|
|
313
|
+
throw new TypeError('adaptive-perf config field "minimalPrompt.suppressSections" must be a boolean');
|
|
314
|
+
}
|
|
315
|
+
if (m.persona !== void 0 && typeof m.persona !== 'string') {
|
|
316
|
+
throw new TypeError('adaptive-perf config field "minimalPrompt.persona" must be a string');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
271
319
|
}
|
|
272
320
|
|
|
273
321
|
// ── 纯函数(导出便于回归测试)────────────────────────────────────────────
|
|
274
322
|
|
|
323
|
+
/** 被极简提示词层屏蔽的全局引导段(name, order,与 dsh-app-boot /
|
|
324
|
+
* dsh-web-app / dsh-system-prompt 的注册一致)。 */
|
|
325
|
+
export const SECTION_SHADOWS = [
|
|
326
|
+
['harness:identity', -100],
|
|
327
|
+
['harness:source', -99],
|
|
328
|
+
['app:web-surface', -98],
|
|
329
|
+
];
|
|
330
|
+
|
|
331
|
+
/** persona 段的注册名与顺序(dsh-system-prompt 的 PERSONA_SECTION/PERSONA_ORDER)。 */
|
|
332
|
+
export const PERSONA_SECTION_NAME = 'deployment:persona';
|
|
333
|
+
export const PERSONA_SECTION_ORDER = 0;
|
|
334
|
+
|
|
275
335
|
/** 提取一条用户消息的顶层文本(text 块拼接)。 */
|
|
276
336
|
export function extractUserText(message) {
|
|
277
337
|
if (message === null || typeof message !== 'object' || !Array.isArray(message.content)) return '';
|
|
@@ -457,9 +517,32 @@ export function apply(ctx, config) {
|
|
|
457
517
|
}
|
|
458
518
|
}
|
|
459
519
|
|
|
520
|
+
/** 应用/更新极简提示词层(persona 阴影 + 全局引导段屏蔽)。 */
|
|
521
|
+
function applyMinimalPrompt(a) {
|
|
522
|
+
for (const disposer of a.promptDisposers) {
|
|
523
|
+
try { disposer(); } catch {}
|
|
524
|
+
}
|
|
525
|
+
a.promptDisposers = [];
|
|
526
|
+
if (!cfg.enabled || !cfg.minimalPrompt.enabled) return;
|
|
527
|
+
const sp = a.agent.ctx.systemPrompt;
|
|
528
|
+
try {
|
|
529
|
+
if (cfg.minimalPrompt.suppressSections) {
|
|
530
|
+
for (const [name, order] of SECTION_SHADOWS) {
|
|
531
|
+
a.promptDisposers.push(sp.section({ name, order, text: '' }));
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const persona = cfg.minimalPrompt.persona.trim();
|
|
535
|
+
if (persona.length > 0) {
|
|
536
|
+
a.promptDisposers.push(sp.section({ name: PERSONA_SECTION_NAME, order: PERSONA_SECTION_ORDER, text: persona }));
|
|
537
|
+
}
|
|
538
|
+
info(`agent ${a.agent.id}: minimal prompt layer active`);
|
|
539
|
+
} catch (error) {
|
|
540
|
+
warn(`minimalPrompt failed for agent ${a.agent.id}: ${error && error.message || error}`);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
460
544
|
/** 应用/更新工具族限制(lean 模式)。总开关关闭、族被禁用、已升级、
|
|
461
|
-
* 已从配置删除的族一律放行。 */
|
|
462
|
-
function applyFamilies(a) {
|
|
545
|
+
* 已从配置删除的族一律放行。 */ function applyFamilies(a) {
|
|
463
546
|
if (!cfg.enabled || !cfg.leanByDefault) {
|
|
464
547
|
for (const [id, disposer] of a.familyDisposers) {
|
|
465
548
|
try { disposer(); } catch {}
|
|
@@ -519,7 +602,10 @@ export function apply(ctx, config) {
|
|
|
519
602
|
const a = {
|
|
520
603
|
agent,
|
|
521
604
|
suppressDisposer: null,
|
|
605
|
+
promptDisposers: [],
|
|
522
606
|
familyDisposers: new Map(),
|
|
607
|
+
bootstrapDisposer: null,
|
|
608
|
+
bootstrapKey: null,
|
|
523
609
|
escalated: new Set(),
|
|
524
610
|
visibleNames: new Set(),
|
|
525
611
|
};
|
|
@@ -536,7 +622,9 @@ export function apply(ctx, config) {
|
|
|
536
622
|
}
|
|
537
623
|
agents.set(agent.id, a);
|
|
538
624
|
applySuppression(a);
|
|
625
|
+
applyMinimalPrompt(a);
|
|
539
626
|
applyFamilies(a);
|
|
627
|
+
syncBootstrap(a);
|
|
540
628
|
info(`agent ${agent.id}: adaptive-perf active (preset ${String(agentPresets.composedPreset(agent.ctx))})`);
|
|
541
629
|
}
|
|
542
630
|
|
|
@@ -549,6 +637,13 @@ export function apply(ctx, config) {
|
|
|
549
637
|
if (a.suppressDisposer !== null) {
|
|
550
638
|
try { a.suppressDisposer(); } catch {}
|
|
551
639
|
}
|
|
640
|
+
for (const disposer of a.promptDisposers) {
|
|
641
|
+
try { disposer(); } catch {}
|
|
642
|
+
}
|
|
643
|
+
a.promptDisposers = [];
|
|
644
|
+
if (a.bootstrapDisposer !== null) {
|
|
645
|
+
try { a.bootstrapDisposer(); } catch {}
|
|
646
|
+
}
|
|
552
647
|
for (const disposer of a.familyDisposers.values()) {
|
|
553
648
|
try { disposer(); } catch {}
|
|
554
649
|
}
|
|
@@ -635,37 +730,60 @@ export function apply(ctx, config) {
|
|
|
635
730
|
return isTarget(agent);
|
|
636
731
|
}
|
|
637
732
|
|
|
638
|
-
|
|
733
|
+
/**
|
|
734
|
+
* bootstrap 阶段的保留工具集:bootstrap 工具对 + PTC 的直接调用工具
|
|
735
|
+
* (run_code)+ compaction 后恢复期的工作集。已晋升返回 null。
|
|
736
|
+
*
|
|
737
|
+
* 注意:不能靠过滤 system-prompt/assemble 的 assembly.tools 来实现——
|
|
738
|
+
* PTC 模式下 assembly.tools 只有 [run_code],Minimal 工具对不在其中,
|
|
739
|
+
* 过滤会触发降级(实测首轮模型仍看到 15 个工具)。正确做法是
|
|
740
|
+
* tools.restrict(与族限制同一机制):它同时驱动 API 目录和 PTC 的
|
|
741
|
+
* SDK 参考段,且天然保留 run_code(不在 deny 里)。
|
|
742
|
+
*/
|
|
743
|
+
function bootstrapKeepSet(a) {
|
|
744
|
+
const phase = bootstrapPhaseOf(a.agent);
|
|
745
|
+
if (phase.promoted) return null;
|
|
746
|
+
const keep = new Set(cfg.bootstrap.tools);
|
|
747
|
+
if (a.visibleNames.has('run_code')) keep.add('run_code');
|
|
748
|
+
if (phase.boundary >= 0) for (const name of cfg.bootstrap.compactionTools) keep.add(name);
|
|
749
|
+
return keep;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/** 按当前阶段同步 bootstrap 的临时 restrict(幂等;仅阶段/配置变化时重挂)。 */
|
|
753
|
+
function syncBootstrap(a) {
|
|
754
|
+
const keep = bootstrapKeepSet(a);
|
|
755
|
+
const key = keep === null ? null : [...keep].sort().join(',');
|
|
756
|
+
if (key === a.bootstrapKey) return;
|
|
757
|
+
if (a.bootstrapDisposer !== null) {
|
|
758
|
+
try { a.bootstrapDisposer(); } catch {}
|
|
759
|
+
a.bootstrapDisposer = null;
|
|
760
|
+
a.bootstrapKey = null;
|
|
761
|
+
}
|
|
762
|
+
if (keep === null) return;
|
|
763
|
+
const deny = [...a.visibleNames].filter((name) => !keep.has(name));
|
|
764
|
+
if (deny.length === 0) return;
|
|
765
|
+
try {
|
|
766
|
+
a.bootstrapDisposer = a.agent.ctx.tools.restrict({ deny });
|
|
767
|
+
a.bootstrapKey = key;
|
|
768
|
+
info(`agent ${a.agent.id}: bootstrap restrict deny=${deny.length} keep=[${[...keep].join(',')}]`);
|
|
769
|
+
} catch (error) {
|
|
770
|
+
warn(`bootstrap restrict failed for agent ${a.agent.id}: ${String((error && error.message) || error)}`);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// 持久事件增量喂入:晋升信号 / compaction 纪元;阶段变化时同步 bootstrap 限制。
|
|
639
775
|
ctx.on('session/event', (session, event) => {
|
|
640
776
|
if (session === null || typeof session !== 'object' || typeof session.id !== 'string') return;
|
|
777
|
+
const before = bootstrapState.get(session.id);
|
|
641
778
|
observePhase(bootstrapState, session.id, event);
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
ctx.on('system-prompt/assemble', async (assembly, _context, next) => {
|
|
648
|
-
const resolved = await next();
|
|
649
|
-
try {
|
|
650
|
-
const agent = agentsService?.currentInitiator?.() ?? void 0;
|
|
651
|
-
if (!bootstrapActiveFor(agent)) return resolved;
|
|
652
|
-
const phase = bootstrapPhaseOf(agent);
|
|
653
|
-
if (phase.promoted) return resolved;
|
|
654
|
-
const keep = new Set(cfg.bootstrap.tools);
|
|
655
|
-
if (phase.boundary >= 0) for (const name of cfg.bootstrap.compactionTools) keep.add(name);
|
|
656
|
-
const filtered = filterBootstrapTools(resolved, keep);
|
|
657
|
-
if (filtered.missing.length > 0) {
|
|
658
|
-
// 目录缺失 bootstrap 工具对:降级为全目录(一次告警),绝不能
|
|
659
|
-
// 把每个请求都卡死在空目录。
|
|
660
|
-
warnBootstrapOnce(`bootstrap tools missing from catalog (${JSON.stringify(filtered.missing)}); exposing the full catalog`);
|
|
661
|
-
return resolved;
|
|
779
|
+
const a = agents.get(session.id);
|
|
780
|
+
if (a !== void 0) {
|
|
781
|
+
const after = bootstrapState.get(session.id);
|
|
782
|
+
if (before === void 0 || after === void 0 || before.promoted !== after.promoted || before.boundary !== after.boundary) {
|
|
783
|
+
syncBootstrap(a);
|
|
662
784
|
}
|
|
663
|
-
return { ...resolved, tools: filtered.tools };
|
|
664
|
-
} catch (error) {
|
|
665
|
-
warnBootstrapOnce(`bootstrap tool filter failed, exposing the full catalog: ${String((error && error.message) || error)}`);
|
|
666
|
-
return resolved;
|
|
667
785
|
}
|
|
668
|
-
}
|
|
786
|
+
});
|
|
669
787
|
|
|
670
788
|
// 首轮剥离自动注入的上下文(技能目录提醒 / AGENTS.md 摘要)。prepend +
|
|
671
789
|
// 根作用域注册保证是最后一道变换(后注册的注入者无法再补回)。
|
|
@@ -722,7 +840,9 @@ export function apply(ctx, config) {
|
|
|
722
840
|
cfg = normalizeConfig({ ...patchConfig, ...merged });
|
|
723
841
|
info('config hot-updated; recomputing restrictions for live agents');
|
|
724
842
|
// 补挂此前创建的会话(例如插件从 disabled 切换为 enabled,或新增了
|
|
725
|
-
// 目标 preset):新符合条件的 agent
|
|
843
|
+
// 目标 preset):新符合条件的 agent 立即接管(handleAgent 已应用全部
|
|
844
|
+
// 层,下面的重算只针对此前已接管的 agent,避免同一 onUpdate 内重复)。
|
|
845
|
+
const existing = new Set(agents.keys());
|
|
726
846
|
if (agentsService !== void 0 && typeof agentsService.list === 'function') {
|
|
727
847
|
try {
|
|
728
848
|
for (const agent of agentsService.list()) handleAgent(agent);
|
|
@@ -730,9 +850,13 @@ export function apply(ctx, config) {
|
|
|
730
850
|
warn(`config-update agent sweep failed: ${error && error.message || error}`);
|
|
731
851
|
}
|
|
732
852
|
}
|
|
733
|
-
for (const
|
|
853
|
+
for (const agentId of existing) {
|
|
854
|
+
const a = agents.get(agentId);
|
|
855
|
+
if (a === void 0) continue;
|
|
734
856
|
applySuppression(a);
|
|
857
|
+
applyMinimalPrompt(a);
|
|
735
858
|
applyFamilies(a);
|
|
859
|
+
syncBootstrap(a);
|
|
736
860
|
}
|
|
737
861
|
},
|
|
738
862
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaoset/adaptive-perf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "DSH host plugin: bring standard / PTC presets to minimal-mode-level performance via runtime-context suppression and adaptive tool-catalog trimming with demand-driven escalation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|