@lmzhen/dsh-evolution-review 0.3.40 → 0.3.42

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.
Files changed (2) hide show
  1. package/lib/index.js +44 -46
  2. package/package.json +10 -10
package/lib/index.js CHANGED
@@ -65,18 +65,22 @@ function apply(ctx, rawConfig) {
65
65
  const completionInjected = /* @__PURE__ */ new Set();
66
66
  const pendingCadenceReviews = /* @__PURE__ */ new Map();
67
67
  const pendingCadenceWarned = /* @__PURE__ */ new Set();
68
+ const skipNextCadenceFire = /* @__PURE__ */ new Map();
69
+ const cadenceResetWarned = /* @__PURE__ */ new Set();
68
70
  let reviewInFlight = false;
69
71
  const policy = () => ctx.get("evolutionPolicy")?.get();
70
72
  ctx.on("session/event", (session, event) => {
71
73
  if (event.type === "turn/start") turnStarts.set(session.id, session.seq - 1);
72
74
  if (event.type !== "turn/end") return;
73
- if (turnStarts.size >= COUNTER_SWEEP_THRESHOLD || cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || completionInjected.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceReviews.size >= COUNTER_SWEEP_THRESHOLD) {
75
+ if (turnStarts.size >= COUNTER_SWEEP_THRESHOLD || cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || completionInjected.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceReviews.size >= COUNTER_SWEEP_THRESHOLD || skipNextCadenceFire.size >= COUNTER_SWEEP_THRESHOLD || cadenceResetWarned.size >= COUNTER_SWEEP_THRESHOLD) {
74
76
  const isAlive = (id) => ctx.agents.get(id) !== void 0;
75
77
  sweepDeadSessionEntries(turnStarts, isAlive);
76
78
  sweepDeadSessionEntries(cumulativeToolCalls, isAlive);
77
79
  sweepDeadSessionEntries(completionInjected, isAlive);
78
80
  sweepDeadSessionEntries(pendingCadenceReviews, isAlive);
79
81
  sweepDeadSessionEntries(pendingCadenceWarned, isAlive);
82
+ sweepDeadSessionEntries(skipNextCadenceFire, isAlive);
83
+ sweepDeadSessionEntries(cadenceResetWarned, isAlive);
80
84
  }
81
85
  onTurnEnd(session, event);
82
86
  });
@@ -110,7 +114,9 @@ function apply(ctx, rawConfig) {
110
114
  lastTurn: -1
111
115
  };
112
116
  const snapshot = policy();
113
- const kind = advanceReview(state, event.data.turn, signal, {
117
+ const skipFire = skipNextCadenceFire.get(session.id) ?? false;
118
+ if (skipFire) skipNextCadenceFire.delete(session.id);
119
+ const rawKind = advanceReview(state, event.data.turn, signal, {
114
120
  memoryInterval: snapshot?.reviewMemoryInterval ?? config.memoryInterval,
115
121
  skillInterval: snapshot?.reviewSkillInterval ?? config.skillInterval,
116
122
  substantiveMinToolCalls: snapshot?.substantiveMinToolCalls ?? 3,
@@ -118,32 +124,16 @@ function apply(ctx, rawConfig) {
118
124
  substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ?? 500,
119
125
  resetOnFire: false
120
126
  });
127
+ const kind = skipFire ? null : rawKind;
121
128
  await stateService?.saveReviewState(session.id, state);
122
129
  const cumulative = (cumulativeToolCalls.get(session.id) ?? 0) + signal.toolCalls;
123
130
  cumulativeToolCalls.set(session.id, cumulative);
124
- const deliverReview = (text) => {
125
- const message = createUserMessage({
126
- content: [{
127
- type: "text",
128
- text
129
- }],
130
- source: {
131
- kind: "plugin",
132
- plugin: "dsh-evolution-review",
133
- form: "notice",
134
- summary: "auto-review"
135
- }
136
- });
137
- const followup = agent.followup;
138
- if (config.reviewWakeInject && typeof followup === "function") followup(message);
139
- else agent.inject(message);
140
- };
141
131
  if (event.data.reason.kind === "completed") {
142
132
  const pendingKind = pendingCadenceReviews.get(session.id) ?? kind ?? void 0;
143
133
  if (pendingKind !== void 0) {
144
134
  pendingCadenceReviews.delete(session.id);
145
135
  if ((policy()?.reviewMode ?? config.reviewMode) === "inject") try {
146
- deliverReview(reviewPrompt(pendingKind));
136
+ deliverMessage(agent, reviewPrompt(pendingKind), "auto-review");
147
137
  } catch (injectError) {
148
138
  ctx.logger.warn(`dsh-evolution-review: deferred review inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
149
139
  }
@@ -155,13 +145,20 @@ function apply(ctx, rawConfig) {
155
145
  assistantChars: signal.assistantChars
156
146
  });
157
147
  else try {
158
- deliverReview(reviewPrompt(pendingKind));
148
+ deliverMessage(agent, reviewPrompt(pendingKind), "auto-review");
159
149
  } catch (injectError) {
160
150
  ctx.logger.warn(`dsh-evolution-review: deferred review inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
161
151
  }
162
152
  state.turnsSinceMemory = 0;
163
153
  state.turnsSinceSkill = 0;
164
- await stateService?.saveReviewState(session.id, state);
154
+ try {
155
+ await stateService?.saveReviewState(session.id, state);
156
+ } catch (resetError) {
157
+ if (!cadenceResetWarned.has(session.id)) {
158
+ cadenceResetWarned.add(session.id);
159
+ ctx.logger.warn(`dsh-evolution-review: cadence counter reset could not be persisted after a delivered review (${resetError instanceof Error ? resetError.message : String(resetError)}) — a stateful reload may re-deliver this review`);
160
+ }
161
+ }
165
162
  }
166
163
  }
167
164
  if (kind && event.data.reason.kind !== "completed") {
@@ -203,6 +200,29 @@ function apply(ctx, rawConfig) {
203
200
  assistantChars: signal.assistantChars
204
201
  });
205
202
  }
203
+ /** V7-03 (0.3.42): shared waking delivery — review prompts AND result
204
+ * notices go through the same followup-first channel (skip the woken turn's
205
+ * cadence fire once, degrade to inject when reviewWakeInject is off or the
206
+ * host lacks followup). */
207
+ const deliverMessage = (agent, text, summary) => {
208
+ const message = createUserMessage({
209
+ content: [{
210
+ type: "text",
211
+ text
212
+ }],
213
+ source: {
214
+ kind: "plugin",
215
+ plugin: "dsh-evolution-review",
216
+ form: "notice",
217
+ summary
218
+ }
219
+ });
220
+ const followup = agent.followup;
221
+ if (config.reviewWakeInject && typeof followup === "function") {
222
+ followup(message);
223
+ skipNextCadenceFire.set(agent.session.id, true);
224
+ } else agent.inject(message);
225
+ };
206
226
  async function trySubagentReview(session, agent, kind, signal) {
207
227
  if ((policy()?.reviewMode ?? config.reviewMode) === "inject") return false;
208
228
  const subagents = ctx.get("subagents");
@@ -274,18 +294,7 @@ function apply(ctx, rawConfig) {
274
294
  const applied = actions.join(" · ");
275
295
  const note = executed.ok ? "" : "\n部分操作失败。以下操作已应用,请勿重复执行。";
276
296
  try {
277
- agent.inject(createUserMessage({
278
- content: [{
279
- type: "text",
280
- text: `💾 Self-improvement review: ${applied}${note}`
281
- }],
282
- source: {
283
- kind: "plugin",
284
- plugin: "dsh-evolution-review",
285
- form: "notice",
286
- summary: "self-improvement review"
287
- }
288
- }));
297
+ deliverMessage(agent, `💾 Self-improvement review: ${applied}${note}`, "self-improvement review");
289
298
  } catch (injectError) {
290
299
  ctx.logger.warn(`dsh-evolution-review: result notice inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
291
300
  }
@@ -298,18 +307,7 @@ function apply(ctx, rawConfig) {
298
307
  if (reasons.length === 0) reasons.push("the review plan contained nothing executable");
299
308
  let text = `💾 Self-improvement review: 0 ops landed. ${reasons.join(" ")}`;
300
309
  if (text.length > 500) text = `${text.slice(0, 497)}…`;
301
- agent.inject(createUserMessage({
302
- content: [{
303
- type: "text",
304
- text
305
- }],
306
- source: {
307
- kind: "plugin",
308
- plugin: "dsh-evolution-review",
309
- form: "notice",
310
- summary: "self-improvement review"
311
- }
312
- }));
310
+ deliverMessage(agent, text, "self-improvement review");
313
311
  } catch (injectError) {
314
312
  ctx.logger.warn(`dsh-evolution-review: zero-landing notice inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
315
313
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-review",
3
3
  "description": "Background review orchestration (community build)",
4
- "version": "0.3.40",
4
+ "version": "0.3.42",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,9 +31,9 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-approval": "^0.3.40",
35
- "@lmzhen/dsh-evolution-core": "^0.3.40",
36
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.40"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.42",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.42",
36
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.42"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.1",
@@ -42,8 +42,8 @@
42
42
  "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
43
43
  "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
44
44
  "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
45
- "@lmzhen/dsh-evolution-state": "^0.3.40",
46
- "@lmzhen/dsh-evolution-policy": "^0.3.40"
45
+ "@lmzhen/dsh-evolution-state": "^0.3.42",
46
+ "@lmzhen/dsh-evolution-policy": "^0.3.42"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
@@ -54,9 +54,9 @@
54
54
  "@deepseek-ai/dsh-session-persistence": "^0.1.1-rc.2",
55
55
  "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.1-rc.2",
56
56
  "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
57
- "@lmzhen/dsh-evolution-approval": "^0.3.40",
58
- "@lmzhen/dsh-evolution-core": "^0.3.40",
59
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.40",
60
- "@lmzhen/dsh-evolution-state": "^0.3.40"
57
+ "@lmzhen/dsh-evolution-approval": "^0.3.42",
58
+ "@lmzhen/dsh-evolution-core": "^0.3.42",
59
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.42",
60
+ "@lmzhen/dsh-evolution-state": "^0.3.42"
61
61
  }
62
62
  }