@lmzhen/dsh-evolution-review 0.3.67 → 0.3.68
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 +69 -49
- package/lib/types/index.d.ts +3 -2
- package/package.json +10 -10
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
4
|
-
import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, 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_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_USER_CHAR_LIMIT, PROMPT_BUNDLE, SkillLibrary, advanceReview, clampedNumber, contentHash, evolutionIoAdapter, foldTurn, redactSecrets, resolveOrigins, resolveRootConfig, resolveSkillsRoot, reviewPrompt, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
4
|
+
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_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, SkillLibrary, advanceReview, assertSkillsRootAliasRetired, clampedNumber, contentHash, evolutionIoAdapter, foldTurn, redactSecrets, resolveOrigins, resolveRootConfig, resolveSkillsRoot, reviewPrompt, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
5
5
|
import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
|
|
6
6
|
//#region lib/types/index.js
|
|
7
7
|
/**
|
|
@@ -10,13 +10,6 @@ import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
|
|
|
10
10
|
*/
|
|
11
11
|
const name = "evolution-review";
|
|
12
12
|
const inject = ["agents"];
|
|
13
|
-
/** Node's 32-bit timer-delay ceiling (`AbortSignal.timeout`/`setTimeout`):
|
|
14
|
-
* a larger value throws RangeError. B-2 (v18): without a max, a misconfigured
|
|
15
|
-
* `reviewTimeoutMs` made `AbortSignal.timeout` throw inside the subagent
|
|
16
|
-
* start call; the outer catch logged it and silently degraded the review to
|
|
17
|
-
* the inject path. The schema and the assembly clamp both reject it (same
|
|
18
|
-
* bound as commands/maintenance). */
|
|
19
|
-
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
20
13
|
const Config = z.object({
|
|
21
14
|
reviewEnabled: z.boolean().default(true),
|
|
22
15
|
reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("subagent"),
|
|
@@ -81,8 +74,8 @@ function clampReviewConfig(rawConfig, ctx) {
|
|
|
81
74
|
function apply(ctx, rawConfig = {}) {
|
|
82
75
|
if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to schedule review work");
|
|
83
76
|
const config = clampReviewConfig(rawConfig, ctx);
|
|
77
|
+
assertSkillsRootAliasRetired(rawConfig);
|
|
84
78
|
const rootConfig = resolveRootConfig(rawConfig);
|
|
85
|
-
if (rootConfig.usedDeprecatedAlias) ctx.logger.warn("evolution-review: config \"skillsRoot\" is deprecated (E-7); use \"root\" — the alias is honoured until 0.3.65");
|
|
86
79
|
const turnStarts = /* @__PURE__ */ new Map();
|
|
87
80
|
let statelessReviewStateWarned = false;
|
|
88
81
|
const cumulativeToolCalls = /* @__PURE__ */ new Map();
|
|
@@ -160,9 +153,9 @@ function apply(ctx, rawConfig = {}) {
|
|
|
160
153
|
advanced.kind = advanceReview(state, event.data.turn, signal, {
|
|
161
154
|
memoryInterval: snapshot?.reviewMemoryInterval ?? config.memoryInterval,
|
|
162
155
|
skillInterval: snapshot?.reviewSkillInterval ?? config.skillInterval,
|
|
163
|
-
substantiveMinToolCalls: snapshot?.substantiveMinToolCalls ??
|
|
164
|
-
substantiveMinUserChars: snapshot?.substantiveMinUserChars ??
|
|
165
|
-
substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ??
|
|
156
|
+
substantiveMinToolCalls: snapshot?.substantiveMinToolCalls ?? DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS,
|
|
157
|
+
substantiveMinUserChars: snapshot?.substantiveMinUserChars ?? DEFAULT_SUBSTANTIVE_MIN_USER_CHARS,
|
|
158
|
+
substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ?? DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS,
|
|
166
159
|
resetOnFire: false
|
|
167
160
|
});
|
|
168
161
|
await stateService?.saveReviewState(session.id, state);
|
|
@@ -205,7 +198,10 @@ function apply(ctx, rawConfig = {}) {
|
|
|
205
198
|
} catch (emitError) {
|
|
206
199
|
ctx.logger.warn(`dsh-evolution-review: review-scheduled emit failed: ${emitError instanceof Error ? emitError.message : String(emitError)}`);
|
|
207
200
|
}
|
|
208
|
-
else if (reviewOutcome
|
|
201
|
+
else if (reviewOutcome === "dropped") {
|
|
202
|
+
pendingCadenceReviews.set(session.id, pendingKind);
|
|
203
|
+
return;
|
|
204
|
+
} else if (reviewOutcome !== "deferred") try {
|
|
209
205
|
deliverMessage(agent, reviewPrompt(pendingKind), "auto-review");
|
|
210
206
|
try {
|
|
211
207
|
ctx.emit("evolution/review-scheduled", {
|
|
@@ -334,22 +330,25 @@ function apply(ctx, rawConfig = {}) {
|
|
|
334
330
|
const subagents = ctx.get("subagents");
|
|
335
331
|
if (!subagents) return false;
|
|
336
332
|
if (reviewInFlight) {
|
|
337
|
-
if (deferredFallbackReviews.length < DEFERRED_REVIEW_CAP)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
333
|
+
if (deferredFallbackReviews.length < DEFERRED_REVIEW_CAP) {
|
|
334
|
+
deferredFallbackReviews.push({
|
|
335
|
+
agent,
|
|
336
|
+
sessionId: session.id,
|
|
337
|
+
kind,
|
|
338
|
+
prompt: reviewPrompt(kind),
|
|
339
|
+
label: "auto-review",
|
|
340
|
+
channel: "inject",
|
|
341
|
+
counts: signal
|
|
342
|
+
});
|
|
343
|
+
return "deferred";
|
|
344
|
+
}
|
|
345
|
+
ctx.logger.warn(`dsh-evolution-review: deferred-review queue at cap (${DEFERRED_REVIEW_CAP}) — dropping one fallback review prompt`);
|
|
346
|
+
return "dropped";
|
|
348
347
|
}
|
|
349
348
|
reviewInFlight = true;
|
|
350
349
|
try {
|
|
351
350
|
const snapshot = policy();
|
|
352
|
-
const model = kind === "memory" ? snapshot?.memoryReviewModel ??
|
|
351
|
+
const model = kind === "memory" ? snapshot?.memoryReviewModel ?? DEFAULT_MEMORY_REVIEW_MODEL : snapshot?.skillReviewModel ?? DEFAULT_SKILL_REVIEW_MODEL;
|
|
353
352
|
const reviewText = redactSecrets(buildReviewRequest(session, kind, signal, config.reviewContextMessages, config.reviewMessageChars));
|
|
354
353
|
const agentOptions = { model };
|
|
355
354
|
if (config.reviewProvider) agentOptions.provider = config.reviewProvider;
|
|
@@ -391,9 +390,38 @@ function apply(ctx, rawConfig = {}) {
|
|
|
391
390
|
});
|
|
392
391
|
const acceptedSkillOps = validation.accepted.skillOps ?? [];
|
|
393
392
|
const skippedUnread = filterUnreadSkillOps(acceptedSkillOps, new Set([...collectReadSkillNames(session), ...childReads]));
|
|
394
|
-
const executed = await withTimeout(executePlan(validation.accepted, session), config.reviewTimeoutMs, "review plan execution");
|
|
395
|
-
const actions = executed.actions;
|
|
396
393
|
const evidenceQuotes = [...validation.accepted.memoryOps ?? [], ...acceptedSkillOps].reduce((total, op) => total + (Array.isArray(op.evidence) ? op.evidence.length : 0), 0);
|
|
394
|
+
const emitApplied = (report) => {
|
|
395
|
+
try {
|
|
396
|
+
ctx.emit("evolution/plan-applied", {
|
|
397
|
+
sessionId: session.id,
|
|
398
|
+
planId: randomUUID(),
|
|
399
|
+
policyFingerprint,
|
|
400
|
+
memoryApplied: report.actions.filter((action) => action.startsWith("Memory")).length,
|
|
401
|
+
skillApplied: report.actions.filter((action) => action.startsWith("Skill ")).length,
|
|
402
|
+
rejectedOps: validation.rejected.length,
|
|
403
|
+
...skippedUnread > 0 ? { skippedUnread } : {},
|
|
404
|
+
executionFailures: report.failedOps?.length ?? 0,
|
|
405
|
+
...report.executionError !== void 0 ? { executionError: report.executionError } : {},
|
|
406
|
+
evidenceQuotes,
|
|
407
|
+
estimatedInputChars: reviewText.length
|
|
408
|
+
});
|
|
409
|
+
} catch (emitError) {
|
|
410
|
+
ctx.logger.warn(`dsh-evolution-review: plan-applied emit failed: ${emitError instanceof Error ? emitError.message : String(emitError)}`);
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
const landed = [];
|
|
414
|
+
let executed;
|
|
415
|
+
try {
|
|
416
|
+
executed = await withTimeout(executePlan(validation.accepted, session, (action) => landed.push(action)), config.reviewTimeoutMs, "review plan execution");
|
|
417
|
+
} catch (error) {
|
|
418
|
+
emitApplied({
|
|
419
|
+
actions: landed,
|
|
420
|
+
executionError: `execution timed out after ${config.reviewTimeoutMs}ms`
|
|
421
|
+
});
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
424
|
+
const actions = executed.actions;
|
|
397
425
|
if (actions.length > 0) {
|
|
398
426
|
const applied = actions.join(" · ");
|
|
399
427
|
const note = executed.ok ? "" : "\n部分操作失败。以下操作已应用,请勿重复执行。";
|
|
@@ -415,23 +443,11 @@ function apply(ctx, rawConfig = {}) {
|
|
|
415
443
|
} catch (injectError) {
|
|
416
444
|
ctx.logger.warn(`dsh-evolution-review: zero-landing notice inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
|
|
417
445
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
memoryApplied: actions.filter((action) => action.startsWith("Memory")).length,
|
|
424
|
-
skillApplied: actions.filter((action) => action.startsWith("Skill ")).length,
|
|
425
|
-
rejectedOps: validation.rejected.length + skippedUnread,
|
|
426
|
-
executionFailures: executed.failedOps.length,
|
|
427
|
-
...executed.aborted !== void 0 ? { executionError: executed.aborted } : {},
|
|
428
|
-
...executed.failedOps[0] !== void 0 && executed.aborted === void 0 ? { executionError: executed.failedOps[0] } : {},
|
|
429
|
-
evidenceQuotes,
|
|
430
|
-
estimatedInputChars: reviewText.length
|
|
431
|
-
});
|
|
432
|
-
} catch (emitError) {
|
|
433
|
-
ctx.logger.warn(`dsh-evolution-review: plan-applied emit failed: ${emitError instanceof Error ? emitError.message : String(emitError)}`);
|
|
434
|
-
}
|
|
446
|
+
emitApplied({
|
|
447
|
+
actions,
|
|
448
|
+
failedOps: executed.failedOps,
|
|
449
|
+
...executed.aborted !== void 0 ? { executionError: executed.aborted } : executed.failedOps[0] !== void 0 ? { executionError: executed.failedOps[0] } : {}
|
|
450
|
+
});
|
|
435
451
|
return true;
|
|
436
452
|
} finally {
|
|
437
453
|
try {
|
|
@@ -470,7 +486,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
470
486
|
}
|
|
471
487
|
}
|
|
472
488
|
}
|
|
473
|
-
async function executePlan(plan, session) {
|
|
489
|
+
async function executePlan(plan, session, onLanded) {
|
|
474
490
|
const sessionId = session?.id;
|
|
475
491
|
const memory = ctx.get("memory");
|
|
476
492
|
const approval = ctx.get("evolutionApproval");
|
|
@@ -497,8 +513,10 @@ function apply(ctx, rawConfig = {}) {
|
|
|
497
513
|
old_text: op.old_text
|
|
498
514
|
};
|
|
499
515
|
const result = approval ? await runApproved("memory", `memory ${normalized.target} ${normalized.action}`, normalized, normalized, session) : await memory?.applyBatch(normalized.target, [normalized]);
|
|
500
|
-
if (result?.ok)
|
|
501
|
-
|
|
516
|
+
if (result?.ok) {
|
|
517
|
+
actions.push("Memory updated");
|
|
518
|
+
onLanded?.("Memory updated");
|
|
519
|
+
} else {
|
|
502
520
|
ok = false;
|
|
503
521
|
failedOps.push(`memory ${normalized.action} ${normalized.target}: ${result?.message ?? "service unavailable"}`);
|
|
504
522
|
}
|
|
@@ -522,8 +540,10 @@ function apply(ctx, rawConfig = {}) {
|
|
|
522
540
|
origin: origins.library
|
|
523
541
|
};
|
|
524
542
|
const result = approval ? await runApproved("skill", `skill ${op.action ?? "patch"} ${op.name}`, runnerArgs, runnerArgs, session) : await executeSkillDirect(args);
|
|
525
|
-
if (result?.ok)
|
|
526
|
-
|
|
543
|
+
if (result?.ok) {
|
|
544
|
+
actions.push(`Skill ${op.name} ${op.action ?? "patch"}`);
|
|
545
|
+
onLanded?.(`Skill ${op.name} ${op.action ?? "patch"}`);
|
|
546
|
+
} else {
|
|
527
547
|
ok = false;
|
|
528
548
|
failedOps.push(`skill ${op.action ?? "patch"} ${op.name}: ${result?.message ?? "service unavailable"}`);
|
|
529
549
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -47,8 +47,9 @@ export interface Config {
|
|
|
47
47
|
* skills in the SAME tree the catalog/tools read instead of writing a
|
|
48
48
|
* parallel tree the rest of the family cannot see. E-7 (v18): canonical key. */
|
|
49
49
|
root?: string;
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
50
|
+
/** V27 G2.4 (M-08): the retired `skillsRoot` alias, kept in the schema so a
|
|
51
|
+
* config that still sets it reaches {@link assertSkillsRootAliasRetired} and
|
|
52
|
+
* fails the load instead of being silently dropped. Never read. */
|
|
52
53
|
skillsRoot?: string;
|
|
53
54
|
}
|
|
54
55
|
export declare const Config: z<Config>;
|
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.
|
|
4
|
+
"version": "0.3.68",
|
|
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.
|
|
35
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
36
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.3.
|
|
34
|
+
"@lmzhen/dsh-evolution-approval": "^0.3.68",
|
|
35
|
+
"@lmzhen/dsh-evolution-core": "^0.3.68",
|
|
36
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.3.68"
|
|
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.
|
|
46
|
-
"@lmzhen/dsh-evolution-policy": "^0.3.
|
|
45
|
+
"@lmzhen/dsh-evolution-state": "^0.3.68",
|
|
46
|
+
"@lmzhen/dsh-evolution-policy": "^0.3.68"
|
|
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.
|
|
58
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
59
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.3.
|
|
60
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
57
|
+
"@lmzhen/dsh-evolution-approval": "^0.3.68",
|
|
58
|
+
"@lmzhen/dsh-evolution-core": "^0.3.68",
|
|
59
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.3.68",
|
|
60
|
+
"@lmzhen/dsh-evolution-state": "^0.3.68"
|
|
61
61
|
}
|
|
62
62
|
}
|