@chaoset/adaptive-perf 0.3.2 → 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 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
@@ -143,6 +143,27 @@ export const DEFAULT_CONFIG = {
143
143
  /** 请求 #1 的输出预算封顶(token);0 = 不封顶(opt-in)。 */
144
144
  maxTokens: 0,
145
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
+ },
146
167
  };
147
168
 
148
169
  /** 轻量配置校验/归一化:非法字段回退默认值,避免 config.json 或 remote.set
@@ -203,6 +224,15 @@ export function normalizeConfig(source, defaults = DEFAULT_CONFIG) {
203
224
  compactionTools: stringListOrEmpty(rawBootstrap.compactionTools, db.compactionTools),
204
225
  maxTokens,
205
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
+ };
206
236
  return {
207
237
  enabled: boolValue(merged.enabled, defaults.enabled),
208
238
  presets: stringList(merged.presets, defaults.presets),
@@ -213,6 +243,7 @@ export function normalizeConfig(source, defaults = DEFAULT_CONFIG) {
213
243
  coreTools: stringList(merged.coreTools, defaults.coreTools),
214
244
  families,
215
245
  bootstrap,
246
+ minimalPrompt,
216
247
  };
217
248
  }
218
249
 
@@ -270,10 +301,37 @@ export function validateConfig(partial) {
270
301
  }
271
302
  }
272
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
+ }
273
319
  }
274
320
 
275
321
  // ── 纯函数(导出便于回归测试)────────────────────────────────────────────
276
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
+
277
335
  /** 提取一条用户消息的顶层文本(text 块拼接)。 */
278
336
  export function extractUserText(message) {
279
337
  if (message === null || typeof message !== 'object' || !Array.isArray(message.content)) return '';
@@ -459,9 +517,32 @@ export function apply(ctx, config) {
459
517
  }
460
518
  }
461
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
+
462
544
  /** 应用/更新工具族限制(lean 模式)。总开关关闭、族被禁用、已升级、
463
- * 已从配置删除的族一律放行。 */
464
- function applyFamilies(a) {
545
+ * 已从配置删除的族一律放行。 */ function applyFamilies(a) {
465
546
  if (!cfg.enabled || !cfg.leanByDefault) {
466
547
  for (const [id, disposer] of a.familyDisposers) {
467
548
  try { disposer(); } catch {}
@@ -521,6 +602,7 @@ export function apply(ctx, config) {
521
602
  const a = {
522
603
  agent,
523
604
  suppressDisposer: null,
605
+ promptDisposers: [],
524
606
  familyDisposers: new Map(),
525
607
  bootstrapDisposer: null,
526
608
  bootstrapKey: null,
@@ -540,6 +622,7 @@ export function apply(ctx, config) {
540
622
  }
541
623
  agents.set(agent.id, a);
542
624
  applySuppression(a);
625
+ applyMinimalPrompt(a);
543
626
  applyFamilies(a);
544
627
  syncBootstrap(a);
545
628
  info(`agent ${agent.id}: adaptive-perf active (preset ${String(agentPresets.composedPreset(agent.ctx))})`);
@@ -554,6 +637,10 @@ export function apply(ctx, config) {
554
637
  if (a.suppressDisposer !== null) {
555
638
  try { a.suppressDisposer(); } catch {}
556
639
  }
640
+ for (const disposer of a.promptDisposers) {
641
+ try { disposer(); } catch {}
642
+ }
643
+ a.promptDisposers = [];
557
644
  if (a.bootstrapDisposer !== null) {
558
645
  try { a.bootstrapDisposer(); } catch {}
559
646
  }
@@ -753,7 +840,9 @@ export function apply(ctx, config) {
753
840
  cfg = normalizeConfig({ ...patchConfig, ...merged });
754
841
  info('config hot-updated; recomputing restrictions for live agents');
755
842
  // 补挂此前创建的会话(例如插件从 disabled 切换为 enabled,或新增了
756
- // 目标 preset):新符合条件的 agent 立即接管。
843
+ // 目标 preset):新符合条件的 agent 立即接管(handleAgent 已应用全部
844
+ // 层,下面的重算只针对此前已接管的 agent,避免同一 onUpdate 内重复)。
845
+ const existing = new Set(agents.keys());
757
846
  if (agentsService !== void 0 && typeof agentsService.list === 'function') {
758
847
  try {
759
848
  for (const agent of agentsService.list()) handleAgent(agent);
@@ -761,8 +850,11 @@ export function apply(ctx, config) {
761
850
  warn(`config-update agent sweep failed: ${error && error.message || error}`);
762
851
  }
763
852
  }
764
- for (const a of agents.values()) {
853
+ for (const agentId of existing) {
854
+ const a = agents.get(agentId);
855
+ if (a === void 0) continue;
765
856
  applySuppression(a);
857
+ applyMinimalPrompt(a);
766
858
  applyFamilies(a);
767
859
  syncBootstrap(a);
768
860
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chaoset/adaptive-perf",
3
- "version": "0.3.2",
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",