@lmzhen/dsh-evolution-review 0.16.1 → 0.17.0-rc.1

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/lib/index.js CHANGED
@@ -2,7 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
4
4
  import { SessionId } from "@deepseek-ai/dsh-session";
5
- import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_USER_CHAR_LIMIT, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, advanceReview, assertSkillsRootAliasRetired, clampedNumber, clearReviewChannel, collectReadSkillNames, contentHash, evidenceKindIndex, evolutionIoAdapter, filterUnreadSkillOps, filterUnreadSkillOps as filterUnreadSkillOps$1, foldTurn, installParamSection, markReviewChannel, newSkillLibrary, paramNamespace, policyStageLimits, readDispatchSignal, readNumberParam, redactSecrets, resolveOrigins, resolveRootConfig, reviewPrompt, sessionAudited, sweepReviewChannelSessions, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
5
+ import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_USER_CHAR_LIMIT, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, advanceReview, assertSkillsRootAliasRetired, clampedNumber, clearReviewChannel, contentHash, evolutionIoAdapter, filterUnreadSkillOps, filterUnreadSkillOps as filterUnreadSkillOps$1, markReviewChannel, newSkillLibrary, paramRowId, policyStageLimits, readDispatchSignal, redactSecrets, resolveOrigins, resolveRootConfig, reviewPrompt, sessionAudited, sessionEvidenceIndex, sessionReadNames, sessionTurnSignals, sweepReviewChannelSessions, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
6
6
  import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
7
7
  /**
8
8
  * Whether a message is a notice this plugin delivered, judged only by durable source fields.
@@ -14,7 +14,8 @@ import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
14
14
  */
15
15
  function isReviewNotice(message) {
16
16
  const source = message.source;
17
- return source?.kind === "plugin" && source.plugin === "dsh-evolution-review" && source.form === "notice";
17
+ if (source?.form !== "notice") return false;
18
+ return source.kind === "evolution-review" || source.kind === "plugin:dsh-evolution-review";
18
19
  }
19
20
  /**
20
21
  * Fold one inbox event into the session's outstanding notice.
@@ -127,8 +128,10 @@ const REVIEW_SETTLE_TIMEOUT = "ReviewSettleTimeout";
127
128
  const name = "evolution-review";
128
129
  const inject = ["agents"];
129
130
  const Config = z.object({
130
- reviewEnabled: z.boolean().default(true),
131
- reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("inject"),
131
+ reviewEnabled: z.boolean().default(true).volatile(),
132
+ reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("inject").volatile(),
133
+ reviewMemoryInterval: z.number().min(1).volatile(),
134
+ reviewSkillInterval: z.number().min(1).volatile(),
132
135
  memoryInterval: z.number().min(1).default(DEFAULT_REVIEW_MEMORY_INTERVAL),
133
136
  skillInterval: z.number().min(1).default(DEFAULT_REVIEW_SKILL_INTERVAL),
134
137
  reviewToolAllow: z.array(z.string()).default(["skill"]),
@@ -141,10 +144,10 @@ const Config = z.object({
141
144
  z.const("cadence"),
142
145
  z.const("completion"),
143
146
  z.const("both")
144
- ]).default(DEFAULT_SKILL_REVIEW_TRIGGER),
145
- reviewWakeInject: z.boolean().default(true),
147
+ ]).default(DEFAULT_SKILL_REVIEW_TRIGGER).volatile(),
148
+ reviewWakeInject: z.boolean().default(true).volatile(),
146
149
  sessionScoped: z.boolean().default(false),
147
- skillReviewCompletionMinToolCalls: z.number().min(1).default(DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS),
150
+ skillReviewCompletionMinToolCalls: z.number().min(1).default(DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS).volatile(),
148
151
  root: z.string().default(""),
149
152
  skillsRoot: z.string().default("")
150
153
  });
@@ -172,53 +175,97 @@ const REVIEW_OUTPUT_SCHEMA = {
172
175
  * kind: memory / skill / combined), both in the queue and in the session log.
173
176
  */
174
177
  const cadenceSummary = (kind) => `auto-review:${kind}`;
178
+ /**
179
+ * G3.1 (0.3.23): clamp one numeric review knob so a 0/negative/NaN/±Infinity value
180
+ * falls back to the package default instead of folding as a "disabled" special value
181
+ * (a 0 interval would fire a review every turn; NaN folds as NaN into the
182
+ * cadence/timeout). The schema `.min(1)` guards the loader path; this clamp also
183
+ * covers NaN/±Infinity (which schemastery lets a bare number schema through) and
184
+ * programmatic assembly. `reviewMaxDepth` clamps to at least 1 because 0 is the
185
+ * historical 0.3.1 maximum-depth defect (a 0 rejects the spawn outright). The warning
186
+ * fires once per key: a live field is read at every use, so an assembly-time list
187
+ * would repeat on each read.
188
+ * @param warned - the keys this caller already warned about.
189
+ * @param warn - the warning sink.
190
+ * @param name - the config key, for the warning.
191
+ * @param value - the value as supplied, or its volatile reference.
192
+ * @param fallback - the package default a corrected value falls back to.
193
+ * @param min - the smallest value the engine can act on.
194
+ * @param max - the largest value the carrier can hold, when bounded.
195
+ * @returns the value the engine may use.
196
+ */
197
+ function clampField(warned, warn, name, value, fallback, min, max) {
198
+ const current = typeof value === "object" ? value.get() : value;
199
+ const result = clampedNumber(current, fallback, max === void 0 ? { min } : {
200
+ min,
201
+ max
202
+ });
203
+ if (current !== void 0 && result !== current && !warned.has(name)) {
204
+ warned.add(name);
205
+ warn(`${name} provided an invalid value; falling back to the default`);
206
+ }
207
+ return result;
208
+ }
209
+ /**
210
+ * The DEPLOYMENT layer of this row, clamped once at assembly: the restart-only
211
+ * numerics (registry tier E2) whose consumers read them from this snapshot. The
212
+ * seven E3 keys are NOT resolved here — they are live (G1 §8.3), and
213
+ * {@link resolveReviewRowSettings} reads them at every use.
214
+ * @param rawConfig - the row config as the platform resolved it.
215
+ * @param ctx - the plugin context, for the clamp warning.
216
+ * @returns the deployment layer with its numerics clamped.
217
+ */
175
218
  function clampReviewConfig(rawConfig, ctx) {
176
- const clamped = [];
177
- const field = (name, value, fallback, min, max) => {
178
- const result = clampedNumber(value, fallback, max === void 0 ? { min } : {
179
- min,
180
- max
181
- });
182
- if (value !== void 0 && result !== value) clamped.push(name);
183
- return result;
219
+ const warned = /* @__PURE__ */ new Set();
220
+ const warn = (message) => {
221
+ ctx.logger.warn("dsh-evolution-review: " + message);
184
222
  };
185
- const config = Object.assign({}, rawConfig, {
186
- memoryInterval: field("memoryInterval", readNumberParam(rawConfig, "reviewMemoryInterval"), DEFAULT_REVIEW_MEMORY_INTERVAL, 1),
187
- skillInterval: field("skillInterval", readNumberParam(rawConfig, "reviewSkillInterval"), DEFAULT_REVIEW_SKILL_INTERVAL, 1),
223
+ const field = (name, value, fallback, min, max) => clampField(warned, warn, name, value, fallback, min, max);
224
+ return Object.assign({}, rawConfig, {
188
225
  reviewTimeoutMs: field("reviewTimeoutMs", rawConfig.reviewTimeoutMs, DEFAULT_REVIEW_TIMEOUT_MS, 1, MAX_TIMER_DELAY_MS),
189
226
  reviewContextMessages: field("reviewContextMessages", rawConfig.reviewContextMessages, DEFAULT_REVIEW_CONTEXT_MESSAGES, 1),
190
227
  reviewMessageChars: field("reviewMessageChars", rawConfig.reviewMessageChars, DEFAULT_REVIEW_MESSAGE_CHARS, 1),
191
- reviewMaxDepth: field("reviewMaxDepth", rawConfig.reviewMaxDepth, 1, 1),
192
- skillReviewCompletionMinToolCalls: field("skillReviewCompletionMinToolCalls", rawConfig.skillReviewCompletionMinToolCalls, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, 1)
228
+ reviewMaxDepth: field("reviewMaxDepth", rawConfig.reviewMaxDepth, 1, 1)
193
229
  });
194
- if (clamped.length > 0) ctx.logger.warn(`dsh-evolution-review: ${clamped.join(", ")} provided an invalid value; falling back to the default`);
195
- return config;
196
230
  }
197
231
  function policySnapshotOf(source) {
198
232
  return source?.get?.();
199
233
  }
200
- /** Schema the platform validates the user layer against; defaults mirror the
201
- * core constants so an empty document resolves to today's behaviour. */
202
- const REVIEW_SETTINGS_SCHEMA = z.object({
203
- reviewSkillInterval: z.number().min(1).default(DEFAULT_REVIEW_SKILL_INTERVAL),
204
- reviewMemoryInterval: z.number().min(1).default(DEFAULT_REVIEW_MEMORY_INTERVAL),
205
- skillReviewTrigger: z.union([
206
- z.const("cadence"),
207
- z.const("completion"),
208
- z.const("both")
209
- ]).default(DEFAULT_SKILL_REVIEW_TRIGGER),
210
- skillReviewCompletionMinToolCalls: z.number().min(1).default(DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS),
211
- reviewEnabled: z.boolean().default(true),
212
- reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("inject"),
213
- reviewWakeInject: z.boolean().default(true)
214
- });
234
+ /**
235
+ * This row's review knobs as they stand RIGHT NOW (G1 §8.3) — the base layer of the
236
+ * precedence chain. The seven E3 keys are live: the platform hands each one a
237
+ * reference it updates in place, so a committed settings edit needs neither a restart
238
+ * nor a watcher. The deprecated cadence aliases stay the fallback spelling of the two
239
+ * interval keys, and every numeric field is clamped (G3.1).
240
+ * @param rawConfig - the row config as the platform resolved it.
241
+ * @param warn - sink for the once-per-key clamp warning.
242
+ * @returns the row layer of the review knobs.
243
+ */
244
+ function resolveReviewRowSettings(rawConfig, warn) {
245
+ const warned = /* @__PURE__ */ new Set();
246
+ return {
247
+ reviewSkillInterval: clampField(warned, warn, "reviewSkillInterval", rawConfig.reviewSkillInterval?.get() ?? rawConfig.skillInterval, DEFAULT_REVIEW_SKILL_INTERVAL, 1),
248
+ reviewMemoryInterval: clampField(warned, warn, "reviewMemoryInterval", rawConfig.reviewMemoryInterval?.get() ?? rawConfig.memoryInterval, DEFAULT_REVIEW_MEMORY_INTERVAL, 1),
249
+ skillReviewTrigger: rawConfig.skillReviewTrigger?.get() ?? DEFAULT_SKILL_REVIEW_TRIGGER,
250
+ skillReviewCompletionMinToolCalls: clampField(warned, warn, "skillReviewCompletionMinToolCalls", rawConfig.skillReviewCompletionMinToolCalls, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, 1),
251
+ reviewEnabled: rawConfig.reviewEnabled?.get() ?? true,
252
+ reviewMode: rawConfig.reviewMode?.get() ?? "inject",
253
+ reviewWakeInject: rawConfig.reviewWakeInject?.get() ?? true
254
+ };
255
+ }
215
256
  function apply(ctx, rawConfig = {}) {
257
+ ctx.inject(["settings"], (injected) => {
258
+ const settings = injected.settings;
259
+ if (typeof settings?.configure !== "function") return;
260
+ const disposer = settings.configure({ auto: false });
261
+ if (typeof disposer === "function") ctx.effect(() => disposer, "dsh-evolution-review: settings presentation");
262
+ });
216
263
  if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to schedule review work");
217
264
  const config = clampReviewConfig(rawConfig, ctx);
218
265
  assertSkillsRootAliasRetired(rawConfig);
219
266
  const rootConfig = resolveRootConfig(rawConfig);
220
267
  const sessionState = new SessionScopedState();
221
- const turnStarts = sessionState.add("turnStarts", /* @__PURE__ */ new Map());
268
+ const dispatchDigest = sessionState.add("dispatchDigest", /* @__PURE__ */ new Map());
222
269
  let statelessReviewStateWarned = false;
223
270
  let channelMarkSuppressedWarned = false;
224
271
  let reviewNoticeOutstandingWarned = false;
@@ -230,42 +277,71 @@ function apply(ctx, rawConfig = {}) {
230
277
  const cadenceResetWarned = sessionState.add("cadenceResetWarned", /* @__PURE__ */ new Set());
231
278
  let reviewInFlight = false;
232
279
  const policy = () => ctx.get("evolutionPolicy")?.get();
233
- const settingsBase = {
234
- reviewSkillInterval: config.skillInterval,
235
- reviewMemoryInterval: config.memoryInterval,
236
- skillReviewTrigger: config.skillReviewTrigger ?? DEFAULT_SKILL_REVIEW_TRIGGER,
237
- skillReviewCompletionMinToolCalls: config.skillReviewCompletionMinToolCalls,
238
- reviewEnabled: config.reviewEnabled ?? true,
239
- reviewMode: config.reviewMode ?? "inject",
240
- reviewWakeInject: config.reviewWakeInject ?? true
241
- };
242
- const overrides = installParamSection(ctx, paramNamespace("evolution-review"), REVIEW_SETTINGS_SCHEMA, settingsBase, { warn: (message) => {
280
+ /**
281
+ * This row's knobs as they stand right now (G1 §8.3): the live fields are resolved
282
+ * per call, so a committed edit needs neither a restart nor a watcher.
283
+ * @returns the row layer of the review settings.
284
+ */
285
+ const rowSettings = () => resolveReviewRowSettings(rawConfig, (message) => {
243
286
  ctx.logger.warn("dsh-evolution-review: " + message);
244
- } });
287
+ });
288
+ /**
289
+ * The keys the user set in this row's namespace (G1 §8.4-A). This is the ONLY
290
+ * remaining read of the settings user layer, and it reads KEY NAMES, never values:
291
+ * the platform resolves the user layer into the row's live fields, so the value
292
+ * comes from `rowSettings()`.
293
+ * @returns the keys present in this row's user layer.
294
+ */
295
+ const userSetKeys = () => {
296
+ const entry = ctx.get("settings")?.describe?.({ redactSecrets: false }).find((item) => item.ns === paramRowId("evolution-review"));
297
+ return new Set(Object.keys(entry?.user ?? {}));
298
+ };
245
299
  const params = () => {
300
+ const row = rowSettings();
301
+ const userSet = userSetKeys();
246
302
  const snapshot = policy();
303
+ const pick = (key) => {
304
+ if (userSet.has(key)) return row[key];
305
+ return snapshot?.[key] ?? row[key];
306
+ };
307
+ const mode = () => {
308
+ if (userSet.has("reviewMode")) return row.reviewMode;
309
+ return snapshot?.reviewMode ?? row.reviewMode;
310
+ };
247
311
  return {
248
- reviewSkillInterval: overrides.get("reviewSkillInterval") ?? snapshot?.reviewSkillInterval ?? config.skillInterval,
249
- reviewMemoryInterval: overrides.get("reviewMemoryInterval") ?? snapshot?.reviewMemoryInterval ?? config.memoryInterval,
250
- skillReviewTrigger: overrides.get("skillReviewTrigger") ?? config.skillReviewTrigger ?? DEFAULT_SKILL_REVIEW_TRIGGER,
251
- skillReviewCompletionMinToolCalls: overrides.get("skillReviewCompletionMinToolCalls") ?? config.skillReviewCompletionMinToolCalls,
252
- reviewEnabled: overrides.get("reviewEnabled") ?? config.reviewEnabled ?? true,
253
- reviewMode: overrides.get("reviewMode") ?? snapshot?.reviewMode ?? config.reviewMode ?? "inject",
254
- reviewWakeInject: overrides.get("reviewWakeInject") ?? config.reviewWakeInject ?? true
312
+ reviewSkillInterval: pick("reviewSkillInterval"),
313
+ reviewMemoryInterval: pick("reviewMemoryInterval"),
314
+ skillReviewTrigger: row.skillReviewTrigger,
315
+ skillReviewCompletionMinToolCalls: row.skillReviewCompletionMinToolCalls,
316
+ reviewEnabled: row.reviewEnabled,
317
+ reviewMode: mode(),
318
+ reviewWakeInject: row.reviewWakeInject
255
319
  };
256
320
  };
257
321
  const schemaDefaults = Config["~standard"].validate({}).value;
322
+ /** The value the schema fills in when nobody sets the key — for a volatile field the
323
+ * reference is always present, so this is what "the row set nothing" resolves to. */
324
+ const SHADOW_DEFAULTS = {
325
+ reviewMode: "inject",
326
+ reviewMemoryInterval: DEFAULT_REVIEW_MEMORY_INTERVAL,
327
+ reviewSkillInterval: DEFAULT_REVIEW_SKILL_INTERVAL
328
+ };
329
+ const rowSupplied = (id, alias) => {
330
+ const canonical = rawConfig[id]?.get();
331
+ if (canonical !== void 0 && canonical !== SHADOW_DEFAULTS[id]) return true;
332
+ return alias !== void 0 && rawConfig[alias] !== void 0 && rawConfig[alias] !== schemaDefaults[alias];
333
+ };
258
334
  const shadowedRowFields = [
259
- "reviewMode",
260
- "memoryInterval",
261
- "skillInterval"
262
- ].filter((field) => rawConfig[field] !== void 0 && rawConfig[field] !== schemaDefaults[field]);
335
+ ["reviewMode", void 0],
336
+ ["reviewMemoryInterval", "memoryInterval"],
337
+ ["reviewSkillInterval", "skillInterval"]
338
+ ].filter(([id, alias]) => !userSetKeys().has(id) && rowSupplied(id, alias)).map(([id]) => id);
263
339
  if (shadowedRowFields.length > 0) {
264
340
  let shadowWarned = false;
265
341
  const warnShadowed = () => {
266
342
  if (shadowWarned) return;
267
343
  shadowWarned = true;
268
- ctx.logger.warn(`dsh-evolution-review: this row sets ${shadowedRowFields.join(", ")}, but the mounted evolution-policy service overrides all three — these row values have no effect. Set them on the evolution-policy row instead.`);
344
+ ctx.logger.warn(`dsh-evolution-review: this row sets ${shadowedRowFields.join(", ")}, but the mounted evolution-policy service overrides ${shadowedRowFields.length === 1 ? "it" : "them"} — these row values have no effect. Set them on the evolution-policy row instead.`);
269
345
  };
270
346
  if (policy() !== void 0) warnShadowed();
271
347
  else ctx.inject(["evolutionPolicy"], () => {
@@ -285,16 +361,16 @@ function apply(ctx, rawConfig = {}) {
285
361
  }
286
362
  ctx.on("session/event", (session, event) => {
287
363
  if (!sessionAudited(ctx, session.id, config.sessionScoped)) return;
288
- if (event.type === "turn/start" && session.header.origin !== "subagent") turnStarts.set(session.id, session.seq - 1);
364
+ appendDispatchFrame(dispatchDigest, session.id, event);
289
365
  if (event.type === "user/message") {
290
366
  if ((event.data?.source)?.kind === "user") clearReviewChannel(session.id);
291
367
  return;
292
368
  }
293
369
  if (event.type !== "turn/end") return;
294
- if (turnStarts.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceWarned.size >= COUNTER_SWEEP_THRESHOLD || cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || completionInjected.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceReviews.size >= COUNTER_SWEEP_THRESHOLD || cadenceResetWarned.size >= COUNTER_SWEEP_THRESHOLD || pendingReviewNotices.size >= COUNTER_SWEEP_THRESHOLD) {
370
+ if (cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || dispatchDigest.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceWarned.size >= COUNTER_SWEEP_THRESHOLD || cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || completionInjected.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceReviews.size >= COUNTER_SWEEP_THRESHOLD || cadenceResetWarned.size >= COUNTER_SWEEP_THRESHOLD || pendingReviewNotices.size >= COUNTER_SWEEP_THRESHOLD) {
295
371
  const isAlive = (id) => ctx.agents.get(id) !== void 0;
296
- sweepDeadSessionEntries(turnStarts, isAlive);
297
372
  sweepDeadSessionEntries(cumulativeToolCalls, isAlive);
373
+ sweepDeadSessionEntries(dispatchDigest, isAlive);
298
374
  sweepDeadSessionEntries(completionInjected, isAlive);
299
375
  sweepDeadSessionEntries(pendingCadenceReviews, isAlive);
300
376
  sweepDeadSessionEntries(pendingCadenceWarned, isAlive);
@@ -379,8 +455,11 @@ function apply(ctx, rawConfig = {}) {
379
455
  if (session.header.origin === "subagent") return;
380
456
  const agent = ctx.agents.get(session.id);
381
457
  if (!agent) return;
382
- const signal = foldTurn(session, turnStarts.get(session.id) ?? Math.max(0, session.seq - 1));
383
- turnStarts.delete(session.id);
458
+ const signal = sessionTurnSignals(ctx, session);
459
+ if (signal === void 0) {
460
+ ctx.logger.warn("dsh-evolution-review: the session cannot be projected (no evolutionSignals state) — this turn is not counted");
461
+ return;
462
+ }
384
463
  const stateService = ctx.get("evolutionState");
385
464
  if (!stateService && !statelessReviewStateWarned) {
386
465
  statelessReviewStateWarned = true;
@@ -614,8 +693,7 @@ function apply(ctx, rawConfig = {}) {
614
693
  text
615
694
  }],
616
695
  source: {
617
- kind: "plugin",
618
- plugin: "dsh-evolution-review",
696
+ kind: "evolution-review",
619
697
  form: "notice",
620
698
  summary
621
699
  }
@@ -720,7 +798,7 @@ function apply(ctx, rawConfig = {}) {
720
798
  try {
721
799
  const snapshot = policy();
722
800
  const model = kind === "memory" ? snapshot?.memoryReviewModel ?? DEFAULT_MEMORY_REVIEW_MODEL : snapshot?.skillReviewModel ?? DEFAULT_SKILL_REVIEW_MODEL;
723
- const reviewText = redactSecrets(buildReviewRequest(session, kind, signal, config.reviewContextMessages, config.reviewMessageChars));
801
+ const reviewText = redactSecrets(buildReviewRequest(session, kind, signal, config.reviewContextMessages, config.reviewMessageChars, dispatchDigest.get(session.id) ?? []));
724
802
  const agentOptions = { model };
725
803
  if (config.reviewProvider) agentOptions.provider = config.reviewProvider;
726
804
  const registry = ctx.get("tools");
@@ -732,7 +810,7 @@ function apply(ctx, rawConfig = {}) {
732
810
  }
733
811
  const preRunHashes = await treeSkillHashes();
734
812
  const sessionSeqAtPlanTime = session.seq - 1;
735
- const substantiveEvidenceSeqs = evidenceKindIndex(session.snapshotEvents());
813
+ const substantiveEvidenceSeqs = sessionEvidenceIndex(ctx, session);
736
814
  const run = await subagents.start("spawn", {
737
815
  label: "dsh-evolution-review",
738
816
  prompt: [{
@@ -760,7 +838,7 @@ function apply(ctx, rawConfig = {}) {
760
838
  ctx.logger.warn(`dsh-evolution-review: review subagent returned no structured plan${stopDetail !== void 0 ? ` (stopReason=${stopDetail}${diagDetail !== void 0 ? `; diagnostic=${diagDetail}` : ""})` : ""}`);
761
839
  return false;
762
840
  }
763
- const childReads = run.localAgent ? collectReadSkillNames(run.localAgent.session.snapshotEvents()) : /* @__PURE__ */ new Set();
841
+ const childReads = run.localAgent ? sessionReadNames(ctx, run.localAgent.session) ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
764
842
  const plan = result.structured;
765
843
  const policyFingerprint = fingerprintPolicy(snapshot);
766
844
  const validation = validateEvolutionPlan(plan, {
@@ -774,7 +852,7 @@ function apply(ctx, rawConfig = {}) {
774
852
  });
775
853
  if (validation.reports.length > 0) ctx.logger.warn(`dsh-evolution-review: ${validation.reports.length} op(s) cite only bookkeeping frames as evidence: ${validation.reports.map((report) => report.reason).join("; ")}`);
776
854
  const acceptedSkillOps = validation.accepted.skillOps ?? [];
777
- const skippedUnread = filterUnreadSkillOps$1(acceptedSkillOps, new Set([...collectReadSkillNames(session.snapshotEvents()), ...childReads]));
855
+ const skippedUnread = filterUnreadSkillOps$1(acceptedSkillOps, new Set([...sessionReadNames(ctx, session) ?? /* @__PURE__ */ new Set(), ...childReads]));
778
856
  const evidenceQuotes = [...validation.accepted.memoryOps ?? [], ...acceptedSkillOps].reduce((total, op) => total + (Array.isArray(op.evidence) ? op.evidence.length : 0), 0);
779
857
  const emitApplied = (report) => {
780
858
  try {
@@ -1159,8 +1237,36 @@ function staleRefusal(result, name, filePath) {
1159
1237
  /** Map/set size that triggers a dead-session counter sweep (bounded, not a hard cap). */
1160
1238
  const COUNTER_SWEEP_THRESHOLD = 128;
1161
1239
  /**
1240
+ * Dispatch frames kept per session for the review digest.
1241
+ *
1242
+ * The digest renders at most 12 tool lines and pairs a result with the call that opened it, so 128
1243
+ * frames (≈64 dispatches) is far more than the renderer can spend — and unlike the whole-log scan it
1244
+ * replaced, the memory this holds is bounded per session rather than proportional to the log.
1245
+ */
1246
+ const DISPATCH_DIGEST_FRAMES = 128;
1247
+ /**
1248
+ * Keep one dispatch-relevant frame in a session's bounded digest.
1249
+ *
1250
+ * A frame is kept when the family's dispatch vocabulary recognizes it as opening a dispatch
1251
+ * (`readDispatchSignal`) or as answering one (`resultCallIdOf`) — the two shapes the digest renders.
1252
+ * Everything else (message frames, boundaries, chunks) is not evidence and is not copied.
1253
+ * @param digest - the per-session digest map.
1254
+ * @param id - the owning session.
1255
+ * @param event - the committed session event.
1256
+ */
1257
+ function appendDispatchFrame(digest, id, event) {
1258
+ if (readDispatchSignal(event) === null && resultCallIdOf(event) === null) return;
1259
+ const frames = digest.get(id) ?? [];
1260
+ frames.push({
1261
+ type: event.type,
1262
+ ...event.data === void 0 ? {} : { data: event.data }
1263
+ });
1264
+ if (frames.length > DISPATCH_DIGEST_FRAMES) frames.splice(0, frames.length - DISPATCH_DIGEST_FRAMES);
1265
+ digest.set(id, frames);
1266
+ }
1267
+ /**
1162
1268
  * Remove every entry whose session is no longer live (rc.42 audit P1-10):
1163
- * `turnStarts` / `cumulativeToolCalls` / `completionInjected` are keyed by
1269
+ * `cumulativeToolCalls` / `completionInjected` / `pendingCadenceReviews` are keyed by
1164
1270
  * SessionId with no platform session-end hook to prune against, so they grew
1165
1271
  * unbounded over a long-lived host. Works for maps and sets; returns the
1166
1272
  * number of removed entries.
@@ -1267,7 +1373,7 @@ function textOfPersistedBlock(block) {
1267
1373
  const candidate = block;
1268
1374
  return candidate.type === "text" && typeof candidate.text === "string" ? candidate.text : "";
1269
1375
  }
1270
- function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars) {
1376
+ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars, dispatchTail = []) {
1271
1377
  const messages = [];
1272
1378
  const surface = session.deriveMessages();
1273
1379
  for (const message of surface.slice(-maxMessages)) if (message.role === "user" || message.role === "assistant") {
@@ -1275,10 +1381,9 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars)
1275
1381
  if (text) messages.push(`${message.role.toUpperCase()}: ${text.slice(0, maxMessageChars)}`);
1276
1382
  }
1277
1383
  const toolLines = [];
1278
- const events = session.snapshotEvents();
1384
+ const events = dispatchTail;
1279
1385
  const callIdentity = /* @__PURE__ */ new Map();
1280
- const identityWindowStart = Math.max(0, events.length - 2e3);
1281
- for (let index = events.length - 1; index >= identityWindowStart; index -= 1) {
1386
+ for (let index = events.length - 1; index >= 0; index -= 1) {
1282
1387
  const event = events[index];
1283
1388
  const opened = readDispatchSignal(event);
1284
1389
  if (opened === null || callIdentity.has(opened.callId)) continue;
@@ -1321,4 +1426,4 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars)
1321
1426
  ].join("\n");
1322
1427
  }
1323
1428
  //#endregion
1324
- export { Config, REVIEW_OUTPUT_SCHEMA, REVIEW_SETTINGS_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, renderToolResultLine, shouldCompletionReview, sweepDeadSessionEntries };
1429
+ export { Config, REVIEW_OUTPUT_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, renderToolResultLine, resolveReviewRowSettings, shouldCompletionReview, sweepDeadSessionEntries };
@@ -2,15 +2,23 @@
2
2
  * Background review orchestration: signal gate → one-shot subagent → trusted plan execution.
3
3
  * @module @lmzhen/dsh-evolution-review
4
4
  */
5
- import type { Context } from '@deepseek-ai/cordis';
5
+ import type { Context, Volatile } from '@deepseek-ai/cordis';
6
6
  import z from '@deepseek-ai/schemastery';
7
+ import type { ContextFormed } from '@deepseek-ai/dsh-llm';
8
+ declare module '@deepseek-ai/dsh-llm' {
9
+ interface MessageSourceMap {
10
+ 'evolution-review': {
11
+ kind: 'evolution-review';
12
+ } & ContextFormed;
13
+ }
14
+ }
7
15
  import type { Session } from '@deepseek-ai/dsh-session';
8
16
  import { type ReviewKind } from '@lmzhen/dsh-evolution-core';
9
17
  export { filterUnreadSkillOps } from '@lmzhen/dsh-evolution-core';
10
18
  export declare const name = "evolution-review";
11
19
  export declare const inject: string[];
12
20
  export interface Config {
13
- reviewEnabled?: boolean;
21
+ reviewEnabled?: Volatile<boolean>;
14
22
  /** How the flush delivers the review: `'inject'` (default since 0.3.74) hands
15
23
  * the review prompt to the PARENT agent — waking it through the same
16
24
  * followup-first channel — so the review runs on the parent's model against
@@ -23,16 +31,21 @@ export interface Config {
23
31
  * at full price. Deployments that prefer the clean-context split switch the
24
32
  * POLICY row (`evolution-policy`): the mounted policy snapshot shadows this
25
33
  * row's value, which the plugin reports once at load (v37 P2-24). */
26
- reviewMode?: 'subagent' | 'inject';
27
- /** Shadowed by the policy snapshot in every shipped composition — configure
28
- * `reviewMemoryInterval` on the `evolution-policy` row instead (v37 P2-24).
29
- * Deprecated alias (G0/S0.3): still readable, refused by writes; removed 0.7.0. */
30
- /** Review cadence in TOOL CALLS (signals.ts: a turn advances by its tool-call count, minimum 1,
31
- * or by 1 when the turn itself carried the memory signal). */
34
+ reviewMode?: Volatile<'subagent' | 'inject'>;
35
+ /** Review cadence in TOOL CALLS — the CANONICAL registry id (G1, signals.ts:
36
+ * a turn advances by its tool-call count, minimum 1, or by 1 when the turn
37
+ * itself carried the memory signal). Shadowed by the policy snapshot in every
38
+ * shipped composition — configure `reviewMemoryInterval` on the
39
+ * `evolution-policy` row instead (v37 P2-24). */
40
+ reviewMemoryInterval?: Volatile<number | undefined>;
41
+ /** Skill-channel review cadence — the CANONICAL registry id (G1); shadowed by
42
+ * the policy snapshot like the memory cadence. */
43
+ reviewSkillInterval?: Volatile<number | undefined>;
44
+ /** Deprecated alias of `reviewMemoryInterval` (G0/S0.3): still readable,
45
+ * refused by writes; removed 0.7.0. */
32
46
  memoryInterval?: number;
33
- /** Shadowed by the policy snapshot in every shipped composition — configure
34
- * `reviewSkillInterval` on the `evolution-policy` row instead. Deprecated
35
- * alias (G0/S0.3): still readable, refused by writes; removed 0.7.0. */
47
+ /** Deprecated alias of `reviewSkillInterval` (G0/S0.3): still readable,
48
+ * refused by writes; removed 0.7.0. */
36
49
  skillInterval?: number;
37
50
  /**
38
51
  * Tools the one-shot review subagent may use. Only actually-existing tools
@@ -56,14 +69,14 @@ export interface Config {
56
69
  * 'completion' does NOT mean "cadence off", and 'both' is effectively
57
70
  * "completion on top of the always-on cadence". The mutually-exclusive
58
71
  * channel reading in earlier docs was wrong. */
59
- skillReviewTrigger?: 'cadence' | 'completion' | 'both';
72
+ skillReviewTrigger?: Volatile<'cadence' | 'completion' | 'both'>;
60
73
  /** Cumulative session tool calls before a session counts as proven-long for the completion channel. */
61
- skillReviewCompletionMinToolCalls?: number;
74
+ skillReviewCompletionMinToolCalls?: Volatile<number>;
62
75
  /** 0.3.40: deliver the deferred review with a WAKING inject for a summary the
63
76
  * model starts immediately (agent.followup — same send() queue, wakeup bit
64
77
  * differs). Default true; false degrades to the non-waking inject (the
65
78
  * summary then waits for the next driver wake). */
66
- reviewWakeInject?: boolean;
79
+ reviewWakeInject?: Volatile<boolean>;
67
80
  /** V10-11 (P2-7): skill tree root for the review's direct skill writes.
68
81
  * Empty (the default) resolves through `resolveSkillsRoot` to the shared
69
82
  * default root — the historical behavior. A custom root keeps review-created
@@ -83,7 +96,45 @@ export interface Config {
83
96
  */
84
97
  sessionScoped?: boolean;
85
98
  }
86
- export declare const Config: z<Config>;
99
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
100
+ reviewEnabled: z<boolean, boolean, "volatile-defined">;
101
+ reviewMode: z<"subagent" | "inject", "subagent" | "inject", "volatile-defined">;
102
+ reviewMemoryInterval: z<number, number, "volatile">;
103
+ reviewSkillInterval: z<number, number, "volatile">;
104
+ memoryInterval: z<number, number, "defined">;
105
+ skillInterval: z<number, number, "defined">;
106
+ reviewToolAllow: z<string[], string[], "defined">;
107
+ reviewTimeoutMs: z<number, number, "defined">;
108
+ reviewContextMessages: z<number, number, "defined">;
109
+ reviewMessageChars: z<number, number, "defined">;
110
+ reviewMaxDepth: z<number, number, "defined">;
111
+ reviewProvider: z<string, string, "plain">;
112
+ skillReviewTrigger: z<"cadence" | "completion" | "both", "cadence" | "completion" | "both", "volatile-defined">;
113
+ reviewWakeInject: z<boolean, boolean, "volatile-defined">;
114
+ sessionScoped: z<boolean, boolean, "defined">;
115
+ skillReviewCompletionMinToolCalls: z<number, number, "volatile-defined">;
116
+ root: z<string, string, "defined">;
117
+ skillsRoot: z<string, string, "defined">;
118
+ }>>, Schemastery.ObjectT<NoInfer<{
119
+ reviewEnabled: z<boolean, boolean, "volatile-defined">;
120
+ reviewMode: z<"subagent" | "inject", "subagent" | "inject", "volatile-defined">;
121
+ reviewMemoryInterval: z<number, number, "volatile">;
122
+ reviewSkillInterval: z<number, number, "volatile">;
123
+ memoryInterval: z<number, number, "defined">;
124
+ skillInterval: z<number, number, "defined">;
125
+ reviewToolAllow: z<string[], string[], "defined">;
126
+ reviewTimeoutMs: z<number, number, "defined">;
127
+ reviewContextMessages: z<number, number, "defined">;
128
+ reviewMessageChars: z<number, number, "defined">;
129
+ reviewMaxDepth: z<number, number, "defined">;
130
+ reviewProvider: z<string, string, "plain">;
131
+ skillReviewTrigger: z<"cadence" | "completion" | "both", "cadence" | "completion" | "both", "volatile-defined">;
132
+ reviewWakeInject: z<boolean, boolean, "volatile-defined">;
133
+ sessionScoped: z<boolean, boolean, "defined">;
134
+ skillReviewCompletionMinToolCalls: z<number, number, "volatile-defined">;
135
+ root: z<string, string, "defined">;
136
+ skillsRoot: z<string, string, "defined">;
137
+ }>>, "plain">;
87
138
  /** V8-01 (0.3.45): the review subagent's structured-output contract. The
88
139
  * `subagents.start` outputSchema is RAW JSON Schema validated by
89
140
  * assertObjectJsonSchema (upstream dsh-tools json-schema.ts — SCHEMA_TYPES
@@ -108,29 +159,26 @@ export declare const REVIEW_OUTPUT_SCHEMA: {
108
159
  };
109
160
  };
110
161
  };
111
- /**
112
- * G3.1 (0.3.23): clamp the numeric review config at assembly so a 0/negative/
113
- * NaN/±Infinity value falls back to the package default instead of folding as a
114
- * "disabled" special value (a 0 interval would fire a review every turn; NaN
115
- * folds as NaN into the cadence/timeout). The schema `.min(1)` guards the
116
- * loader path; this clamp also covers NaN/±Infinity (which schemastery lets a
117
- * bare number schema through) and direct construction. `reviewMaxDepth` clamps
118
- * to at least 1 because 0 is the historical 0.3.1 maximum-depth defect (a 0
119
- * rejects the spawn outright). Warn once when a user-supplied value had to be
120
- * corrected.
121
- */
122
- /** F5 (P2-16, v11): the clamp sets exactly these seven numeric fields — the
162
+ /** F5 (P2-16, v11): the clamp sets exactly these four numeric fields — the
123
163
  * old `as Required<Config>` lied about `reviewToolAllow` etc. being populated
124
- * (`[...undefined]` TypeErrors under a direct `apply(ctx, {})`). */
164
+ * (`[...undefined]` TypeErrors under a direct `apply(ctx, {})`).
165
+ * G1: the seven E3 keys left this list — they are live and resolved at USE time by
166
+ * {@link resolveReviewRowSettings}, which clamps its own numerics. */
125
167
  type ClampedReviewConfig = Config & {
126
- memoryInterval: number;
127
- skillInterval: number;
128
168
  reviewTimeoutMs: number;
129
169
  reviewContextMessages: number;
130
170
  reviewMessageChars: number;
131
171
  reviewMaxDepth: number;
132
- skillReviewCompletionMinToolCalls: number;
133
172
  };
173
+ /**
174
+ * The DEPLOYMENT layer of this row, clamped once at assembly: the restart-only
175
+ * numerics (registry tier E2) whose consumers read them from this snapshot. The
176
+ * seven E3 keys are NOT resolved here — they are live (G1 §8.3), and
177
+ * {@link resolveReviewRowSettings} reads them at every use.
178
+ * @param rawConfig - the row config as the platform resolved it.
179
+ * @param ctx - the plugin context, for the clamp warning.
180
+ * @returns the deployment layer with its numerics clamped.
181
+ */
134
182
  export declare function clampReviewConfig(rawConfig: Config, ctx: Context): ClampedReviewConfig;
135
183
  /** Review behaviour a user may change (G3/S3.1). Field names are the CANONICAL
136
184
  * parameter ids from the registry, so the settings document, the params output,
@@ -153,17 +201,30 @@ export interface ReviewSettings {
153
201
  /** Deliver the deferred review as a waking follow-up message. */
154
202
  reviewWakeInject: boolean;
155
203
  }
156
- /** Schema the platform validates the user layer against; defaults mirror the
157
- * core constants so an empty document resolves to today's behaviour. */
158
- export declare const REVIEW_SETTINGS_SCHEMA: z<ReviewSettings>;
204
+ /**
205
+ * This row's review knobs as they stand RIGHT NOW (G1 §8.3) — the base layer of the
206
+ * precedence chain. The seven E3 keys are live: the platform hands each one a
207
+ * reference it updates in place, so a committed settings edit needs neither a restart
208
+ * nor a watcher. The deprecated cadence aliases stay the fallback spelling of the two
209
+ * interval keys, and every numeric field is clamped (G3.1).
210
+ * @param rawConfig - the row config as the platform resolved it.
211
+ * @param warn - sink for the once-per-key clamp warning.
212
+ * @returns the row layer of the review knobs.
213
+ */
214
+ export declare function resolveReviewRowSettings(rawConfig: Config, warn: (message: string) => void): ReviewSettings;
159
215
  export declare function apply(ctx: Context, rawConfig?: Config): void;
160
216
  /** Completion-channel decision: task finished normally AND the session is proven long. */
161
217
  export declare function shouldCompletionReview(reason: {
162
218
  kind?: string;
163
219
  } | undefined, sessionToolCalls: number, minToolCalls: number): boolean;
220
+ /** One dispatch frame the review digest can render (a native call/result or a PTC sub-dispatch). */
221
+ interface ReviewDispatchFrame {
222
+ readonly type: string;
223
+ readonly data?: unknown;
224
+ }
164
225
  /**
165
226
  * Remove every entry whose session is no longer live (rc.42 audit P1-10):
166
- * `turnStarts` / `cumulativeToolCalls` / `completionInjected` are keyed by
227
+ * `cumulativeToolCalls` / `completionInjected` / `pendingCadenceReviews` are keyed by
167
228
  * SessionId with no platform session-end hook to prune against, so they grew
168
229
  * unbounded over a long-lived host. Works for maps and sets; returns the
169
230
  * number of removed entries.
@@ -196,5 +257,5 @@ export declare function buildReviewRequest(session: Session, kind: ReviewKind, s
196
257
  toolCalls: number;
197
258
  userChars: number;
198
259
  assistantChars: number;
199
- }, maxMessages: number, maxMessageChars: number): string;
260
+ }, maxMessages: number, maxMessageChars: number, dispatchTail?: readonly ReviewDispatchFrame[]): string;
200
261
  //# sourceMappingURL=index.d.ts.map
@@ -18,14 +18,24 @@
18
18
  * whole rule testable without a host.
19
19
  * @module @lmzhen/dsh-evolution-review/review-notice
20
20
  */
21
- /** The plugin id every notice of this plugin carries in its durable message source. */
22
- export declare const REVIEW_NOTICE_PLUGIN = "dsh-evolution-review";
21
+ /** The producer-owned source kind every notice of this plugin carries (0.2.x: each
22
+ * producer declares its own kind; there is no shared catch-all `plugin` kind). */
23
+ export declare const REVIEW_NOTICE_KIND = "evolution-review";
24
+ /**
25
+ * The kind a notice persisted before the 0.2.x line reads back as.
26
+ *
27
+ * The platform's session-format v3→v4 migration rewrites the released shared
28
+ * `{ kind: 'plugin', plugin }` source into `plugin:<plugin>` for a producer its own tables do
29
+ * not know (session-format-v3-to-v4/src/sources.ts:59-65, :74-90), so the notices an
30
+ * upgraded session already carries must still be recognized — otherwise the window they
31
+ * belonged to would be delivered a second time.
32
+ */
33
+ export declare const REVIEW_NOTICE_LEGACY_KIND = "plugin:dsh-evolution-review";
23
34
  /** The subset of a platform message this module reads. */
24
35
  export interface NoticeMessage {
25
36
  readonly id: string;
26
37
  readonly source?: {
27
38
  readonly kind?: string;
28
- readonly plugin?: string;
29
39
  readonly form?: string;
30
40
  } | undefined;
31
41
  }
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.16.1",
4
+ "version": "0.17.0-rc.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,31 +27,31 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.1",
30
- "@lmzhen/dsh-evolution-approval": "^0.16.1",
31
- "@lmzhen/dsh-evolution-core": "^0.16.1",
32
- "@lmzhen/dsh-evolution-plan-validator": "^0.16.1"
30
+ "@lmzhen/dsh-evolution-approval": "^0.17.0-rc.1",
31
+ "@lmzhen/dsh-evolution-core": "^0.17.0-rc.1",
32
+ "@lmzhen/dsh-evolution-plan-validator": "^0.17.0-rc.1"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@deepseek-ai/cordis": "^4.0.1",
36
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
37
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
38
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
39
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
40
- "@lmzhen/dsh-evolution-state": "^0.16.1",
41
- "@lmzhen/dsh-evolution-policy": "^0.16.1"
36
+ "@deepseek-ai/dsh-agent": "^0.2.0-rc.1",
37
+ "@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
38
+ "@deepseek-ai/dsh-session": "^0.2.0-rc.1",
39
+ "@deepseek-ai/dsh-tools": "^0.2.0-rc.1",
40
+ "@lmzhen/dsh-evolution-state": "^0.17.0-rc.1",
41
+ "@lmzhen/dsh-evolution-policy": "^0.17.0-rc.1"
42
42
  },
43
43
  "devDependencies": {
44
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
45
- "@deepseek-ai/dsh-agent-loop-testkit": "^0.1.5-rc.2",
46
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
47
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
48
- "@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.2",
49
- "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.5-rc.2",
50
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
51
- "@lmzhen/dsh-evolution-approval": "^0.16.1",
52
- "@lmzhen/dsh-evolution-core": "^0.16.1",
53
- "@lmzhen/dsh-evolution-curator": "^0.16.1",
54
- "@lmzhen/dsh-evolution-plan-validator": "^0.16.1",
55
- "@lmzhen/dsh-evolution-state": "^0.16.1"
44
+ "@deepseek-ai/dsh-agent": "^0.2.0-rc.1",
45
+ "@deepseek-ai/dsh-agent-loop-testkit": "^0.2.0-rc.1",
46
+ "@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
47
+ "@deepseek-ai/dsh-session": "^0.2.0-rc.1",
48
+ "@deepseek-ai/dsh-session-persistence": "^0.2.0-rc.1",
49
+ "@deepseek-ai/dsh-session-persistence-jsonl": "^0.2.0-rc.1",
50
+ "@deepseek-ai/dsh-tools": "^0.2.0-rc.1",
51
+ "@lmzhen/dsh-evolution-approval": "^0.17.0-rc.1",
52
+ "@lmzhen/dsh-evolution-core": "^0.17.0-rc.1",
53
+ "@lmzhen/dsh-evolution-curator": "^0.17.0-rc.1",
54
+ "@lmzhen/dsh-evolution-plan-validator": "^0.17.0-rc.1",
55
+ "@lmzhen/dsh-evolution-state": "^0.17.0-rc.1"
56
56
  }
57
57
  }