dsh-whale-loli 0.5.2 → 0.5.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 CHANGED
@@ -96,6 +96,18 @@ Cannot read properties of undefined (reading 'kind')
96
96
  连 `step/start` 都没有,极难定位。所以无论裁剪成功、失败还是跳过,都必须 `return next()`。
97
97
  `verify-history-window.mjs` 第 9 组用例复刻了这个 waterfall 语义,并保留了一个「老写法必崩」的反例。
98
98
 
99
+ #### ⚠️ 裁剪写的事件必须带合法 `turn`
100
+
101
+ 宿主的会话格式校验(`dsh-session-format-v3-to-v4`)要求 `developer/message` 的 `turn` 是**正整数**。
102
+ 写死 `turn: 0` 会抛:
103
+
104
+ ```
105
+ developer/message turn must be positive
106
+ ```
107
+
108
+ 所以 `pruneHistory()` 从 `agent/pre-step` 的 payload 里取真实的 `turn` / `step` 透传;
109
+ **拿不到正数 turn 就跳过本次裁剪**(宁可不裁,也不写非法事件)。第 10 组用例覆盖这个分支。
110
+
99
111
  ### 为什么用「提示变量」而不是 section(重要)
100
112
 
101
113
  `@deepseek-ai/dsh-system-prompt` 的 `assemble()` 末尾有这样一段:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-whale-loli",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "鲸鱼娘 Agent 预设(三个)— 极简模式工具面 + 鲸鱼娘·小鱼人设 + 跨会话长期记忆 + 真正生效的 20 轮历史窗口。记忆分「固定记忆」(永久保留)/「滚动摘要」(每轮都记,最多 80 条 FIFO,超限每轮结束自动归档到 archive/<预设名>/)/「最近详细区」/「归档索引」四区,经提示变量注入(persona 为 complete:true,独立 section 会被宿主丢弃);history-window 用宿主表层替换真的裁掉 20 轮以前的历史,不调 LLM、不切断工具配对,并正确放行 agent/pre-step 的 waterfall。",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -137,10 +137,23 @@ export function shadowedNodes(session, startSeq, endSeq) {
137
137
  return nodes.filter((seq) => seq >= startSeq && seq <= endSeq);
138
138
  }
139
139
 
140
- /** 执行裁剪。返回计划;无需裁剪返回 null。 */
141
- export function pruneHistory(agent, keepTurns = DEFAULT_KEEP_TURNS) {
140
+ /**
141
+ * 执行裁剪。返回计划;无需裁剪(或拿不到合法 position)返回 null。
142
+ *
143
+ * `position` = `{ turn, step }`,直接来自 `agent/pre-step` 的 payload。
144
+ * **必须传真实 turn**:宿主 `dsh-session-format-v3-to-v4` 的校验器要求
145
+ * `developer/message` 的 `turn` 为正整数,写死 0 会抛
146
+ * `developer/message turn must be positive`
147
+ * 拿不到正数 turn 就跳过这一轮(宁可不裁,也不写非法事件)。
148
+ */
149
+ export function pruneHistory(agent, keepTurns = DEFAULT_KEEP_TURNS, position = {}) {
142
150
  const session = agent?.session;
143
151
  if (session === undefined) return null;
152
+
153
+ const turn = Number.isInteger(position?.turn) && position.turn > 0 ? position.turn : null;
154
+ if (turn === null) return null;
155
+ const step = Number.isInteger(position?.step) && position.step > 0 ? position.step : 1;
156
+
144
157
  const plan = planPrune(session, keepTurns);
145
158
  if (plan === null) return null;
146
159
 
@@ -150,8 +163,8 @@ export function pruneHistory(agent, keepTurns = DEFAULT_KEEP_TURNS) {
150
163
  session.append(
151
164
  'developer/message',
152
165
  {
153
- turn: 0,
154
- step: 0,
166
+ turn,
167
+ step,
155
168
  message: {
156
169
  role: 'developer',
157
170
  content: [{ type: 'text', text: noticeText(plan.removedTurns, plan.keptTurns) }],
@@ -196,13 +209,16 @@ export function apply(ctx, config = {}) {
196
209
 
197
210
  const keepTurns = typeof config.keepTurns === 'number' ? config.keepTurns : DEFAULT_KEEP_TURNS;
198
211
 
199
- // agent/pre-step 在派生历史之前运行,且拿得到本 agent。
212
+ // agent/pre-step 在派生历史之前运行,且拿得到本 agent 与当前 turn/step。
200
213
  ctx.effect(
201
214
  () =>
202
215
  ctx.on('agent/pre-step', async (payload, next) => {
203
216
  try {
204
217
  const agent = payload?.agent ?? payload?.handle?.agent;
205
- if (agent?.session !== undefined) pruneHistory(agent, keepTurns);
218
+ if (agent?.session !== undefined) {
219
+ // turn/step 必须原样透传给 pruneHistory:宿主校验器要求 turn 为正整数。
220
+ pruneHistory(agent, keepTurns, { turn: payload?.turn, step: payload?.step });
221
+ }
206
222
  } catch {
207
223
  // 裁剪失败绝不影响正常对话
208
224
  }