@shgroup/dsh-serenity-hooks 1.18.3 → 1.18.4

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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.18.3",
3
+ "version": "1.18.4",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/loop + 拦截缝机械约束(safe-mode/路径守卫/会话落盘)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。私有(dsh-external 组织)。",
6
6
  "engines": {
package/lib/index.js CHANGED
@@ -3527,9 +3527,14 @@ const DEFAULT_COMPACTION_TOOLS = [
3527
3527
  /** 默认首轮锚定消息(用户指定:persona 设定 + we/us 人称——首轮模型以 we/us 自称,
3528
3528
  * 对齐 anchored 实测的 "we" 轨迹特征) */
3529
3529
  const DEFAULT_ANCHOR_MESSAGE = "You are a helpful software engineer assistant.The personal pronoun is us/we.";
3530
- /** 构建一个 epoch 感知晋升跟踪器(纯逻辑,可单测) */
3531
- function createEpochPromotion(promoteEvents) {
3532
- /** sessionId -> { boundary, promoted } */
3530
+ /**
3531
+ * 构建一个 epoch 感知晋升跟踪器(纯逻辑,可单测)。
3532
+ * requiredSignals:晋升所需信号数(boundary 后累计;默认 1)。
3533
+ * 多轮锚定(v4):两轮递进锚定时 requiredSignals = 锚定轮数——
3534
+ * 每条锚定回复(assistant/message)计一次,最后一条回复后晋升。
3535
+ */
3536
+ function createEpochPromotion(promoteEvents, requiredSignals = 1) {
3537
+ /** sessionId -> { boundary, signalCount }(boundary 后晋升信号计数) */
3533
3538
  const state = /* @__PURE__ */ new Map();
3534
3539
  const sessionIdOf = (session) => {
3535
3540
  if (session && typeof session === "object") {
@@ -3539,24 +3544,27 @@ function createEpochPromotion(promoteEvents) {
3539
3544
  };
3540
3545
  const scan = (session) => {
3541
3546
  let boundary = -1;
3542
- let promoted = false;
3547
+ let signalCount = 0;
3543
3548
  const events = session?.events;
3544
3549
  if (Array.isArray(events)) for (const event of events) {
3545
3550
  const e = event;
3546
3551
  const seq = typeof e.seq === "number" ? e.seq : 0;
3547
3552
  if (e.type === "compaction/end") {
3548
3553
  boundary = seq;
3549
- promoted = false;
3554
+ signalCount = 0;
3550
3555
  continue;
3551
3556
  }
3552
- if (promoteEvents.has(e.type) && seq > boundary) promoted = true;
3557
+ if (promoteEvents.has(e.type) && seq > boundary) signalCount++;
3553
3558
  }
3554
3559
  const entry = {
3555
3560
  boundary,
3556
- promoted
3561
+ promoted: signalCount >= requiredSignals
3557
3562
  };
3558
3563
  const sid = sessionIdOf(session);
3559
- if (sid) state.set(sid, entry);
3564
+ if (sid) state.set(sid, {
3565
+ boundary,
3566
+ signalCount
3567
+ });
3560
3568
  return entry;
3561
3569
  };
3562
3570
  return {
@@ -3579,7 +3587,12 @@ function createEpochPromotion(promoteEvents) {
3579
3587
  boundary: -1,
3580
3588
  promoted: true
3581
3589
  };
3582
- return state.get(sid) ?? scan(session);
3590
+ const s = state.get(sid);
3591
+ if (s) return {
3592
+ boundary: s.boundary,
3593
+ promoted: s.signalCount >= requiredSignals
3594
+ };
3595
+ return scan(session);
3583
3596
  },
3584
3597
  observe(session, event) {
3585
3598
  const sid = sessionIdOf(session);
@@ -3591,13 +3604,13 @@ function createEpochPromotion(promoteEvents) {
3591
3604
  if (e.type === "compaction/end") {
3592
3605
  state.set(sid, {
3593
3606
  boundary: seq,
3594
- promoted: false
3607
+ signalCount: 0
3595
3608
  });
3596
3609
  return;
3597
3610
  }
3598
- if (promoteEvents.has(e.type) && seq > entry.boundary && !entry.promoted) state.set(sid, {
3599
- ...entry,
3600
- promoted: true
3611
+ if (promoteEvents.has(e.type) && seq > entry.boundary) state.set(sid, {
3612
+ boundary: entry.boundary,
3613
+ signalCount: entry.signalCount + 1
3601
3614
  });
3602
3615
  }
3603
3616
  };
@@ -3620,12 +3633,18 @@ function sourceList(value, field, fallback) {
3620
3633
  function resolveBootstrapSettings(opts) {
3621
3634
  const promoteOn = opts.promoteOn ?? "either";
3622
3635
  if (promoteOn !== "either" && promoteOn !== "tool-call" && promoteOn !== "assistant-message") throw new TypeError(`bootstrap: promoteOn must be one of "tool-call", "assistant-message", "either"; got ${JSON.stringify(promoteOn)}`);
3636
+ let anchorMessages;
3637
+ if (Array.isArray(opts.anchorMessages)) {
3638
+ if (opts.anchorMessages.length === 0 || opts.anchorMessages.some((m) => typeof m !== "string" || m.length === 0)) throw new TypeError(`bootstrap: anchorMessages must be a non-empty array of non-empty strings`);
3639
+ anchorMessages = opts.anchorMessages;
3640
+ } else anchorMessages = [typeof opts.anchorMessage === "string" && opts.anchorMessage.length > 0 ? opts.anchorMessage : DEFAULT_ANCHOR_MESSAGE];
3623
3641
  return {
3624
3642
  bootstrapTools: stringList(opts.bootstrapTools, "bootstrapTools", DEFAULT_BOOTSTRAP_TOOLS),
3625
3643
  promoteEvents: opts.zeroTools ? PROMOTE_EVENTS["assistant-message"] : PROMOTE_EVENTS[promoteOn],
3644
+ requiredSignals: opts.zeroTools ? anchorMessages.length : 1,
3626
3645
  suppressedSources: sourceList(opts.suppressedContextSources, "suppressedContextSources", DEFAULT_SUPPRESSED_SOURCES),
3627
3646
  compactionTools: stringList(opts.compactionTools, "compactionTools", DEFAULT_COMPACTION_TOOLS),
3628
- anchorMessage: typeof opts.anchorMessage === "string" && opts.anchorMessage.length > 0 ? opts.anchorMessage : DEFAULT_ANCHOR_MESSAGE,
3647
+ anchorMessages,
3629
3648
  zeroTools: opts.zeroTools === true
3630
3649
  };
3631
3650
  }
@@ -3656,6 +3675,7 @@ function readBootstrapConfig(agent) {
3656
3675
  suppressedContextSources: b?.suppressedContextSources,
3657
3676
  compactionTools: b?.compactionTools,
3658
3677
  anchorMessage: b?.anchorMessage,
3678
+ anchorMessages: b?.anchorMessages,
3659
3679
  zeroTools: b?.zeroTools
3660
3680
  });
3661
3681
  }
@@ -3665,7 +3685,7 @@ function registerBootstrap(ctx) {
3665
3685
  const trackerFor = (root, settings) => {
3666
3686
  let t = trackers.get(root);
3667
3687
  if (!t) {
3668
- t = createEpochPromotion(settings.promoteEvents);
3688
+ t = createEpochPromotion(settings.promoteEvents, settings.requiredSignals);
3669
3689
  trackers.set(root, t);
3670
3690
  }
3671
3691
  return t;
@@ -3692,12 +3712,12 @@ function registerBootstrap(ctx) {
3692
3712
  if (message?.source?.kind === "plugin") return;
3693
3713
  const inbox = agent.inbox;
3694
3714
  if (!inbox?.prepend) return;
3695
- inbox.prepend("next-turn", {
3696
- id: `bootstrap-anchor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
3715
+ for (let i = settings.anchorMessages.length - 1; i >= 0; i--) inbox.prepend("next-turn", {
3716
+ id: `bootstrap-anchor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}-${i}`,
3697
3717
  role: "user",
3698
3718
  content: [{
3699
3719
  type: "text",
3700
- text: settings.anchorMessage
3720
+ text: settings.anchorMessages[i]
3701
3721
  }],
3702
3722
  source: {
3703
3723
  kind: "plugin",
@@ -3706,7 +3726,7 @@ function registerBootstrap(ctx) {
3706
3726
  summary: "bootstrap anchor turn"
3707
3727
  }
3708
3728
  });
3709
- warnOnce(`anchor turn injected: "${settings.anchorMessage.slice(0, 40)}…"`);
3729
+ warnOnce(`anchor turns injected: ${settings.anchorMessages.length} 条(${settings.anchorMessages[0].slice(0, 40)}…)`);
3710
3730
  } catch {}
3711
3731
  });
3712
3732
  let warned = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.18.3",
3
+ "version": "1.18.4",
4
4
  "description": "宁静号 ACC harness — Native Cordis 插件(DeepSeek Harness 运行时)。真实 DSH 工具注册(cc_fs/session/acc_msm 等 9 工具)+ 拦截缝机械约束(safe-mode/路径守卫/会话落盘)+ 系统提示词注入(ACC/CCE/Constraints/SKILL/Session 五块)。适配 DSH 公开版(deepseek-ai/deepseek-harness 0.1.0-rc)。",
5
5
  "license": "MIT",
6
6
  "repository": {