@lmzhen/dsh-evolution-review 0.16.0 → 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 +183 -78
- package/lib/types/index.d.ts +97 -36
- package/lib/types/review-notice.d.ts +13 -3
- package/package.json +22 -22
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,
|
|
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
|
-
|
|
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
|
|
177
|
-
const
|
|
178
|
-
|
|
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
|
|
186
|
-
|
|
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
|
-
/**
|
|
201
|
-
*
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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:
|
|
249
|
-
reviewMemoryInterval:
|
|
250
|
-
skillReviewTrigger:
|
|
251
|
-
skillReviewCompletionMinToolCalls:
|
|
252
|
-
reviewEnabled:
|
|
253
|
-
reviewMode:
|
|
254
|
-
reviewWakeInject:
|
|
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((
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
383
|
-
|
|
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: "
|
|
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 =
|
|
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 ?
|
|
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([...
|
|
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
|
-
* `
|
|
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 =
|
|
1384
|
+
const events = dispatchTail;
|
|
1279
1385
|
const callIdentity = /* @__PURE__ */ new Map();
|
|
1280
|
-
|
|
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,
|
|
1429
|
+
export { Config, REVIEW_OUTPUT_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, renderToolResultLine, resolveReviewRowSettings, shouldCompletionReview, sweepDeadSessionEntries };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
*
|
|
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
|
-
/**
|
|
34
|
-
*
|
|
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<
|
|
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
|
-
/**
|
|
157
|
-
*
|
|
158
|
-
|
|
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
|
-
* `
|
|
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
|
|
22
|
-
|
|
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.
|
|
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.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
32
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.
|
|
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.
|
|
37
|
-
"@deepseek-ai/dsh-llm": "^0.
|
|
38
|
-
"@deepseek-ai/dsh-session": "^0.
|
|
39
|
-
"@deepseek-ai/dsh-tools": "^0.
|
|
40
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
41
|
-
"@lmzhen/dsh-evolution-policy": "^0.
|
|
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.
|
|
45
|
-
"@deepseek-ai/dsh-agent-loop-testkit": "^0.
|
|
46
|
-
"@deepseek-ai/dsh-llm": "^0.
|
|
47
|
-
"@deepseek-ai/dsh-session": "^0.
|
|
48
|
-
"@deepseek-ai/dsh-session-persistence": "^0.
|
|
49
|
-
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.
|
|
50
|
-
"@deepseek-ai/dsh-tools": "^0.
|
|
51
|
-
"@lmzhen/dsh-evolution-approval": "^0.
|
|
52
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
53
|
-
"@lmzhen/dsh-evolution-curator": "^0.
|
|
54
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.
|
|
55
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
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
|
}
|