@lmzhen/dsh-evolution-review 0.3.61 → 0.3.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/lib/index.js +19 -12
- package/lib/types/index.d.ts +0 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -28,12 +28,13 @@ Independent of request-prefix construction. This package does not alter the asse
|
|
|
28
28
|
- The completion-channel counters (`cumulativeToolCalls` / `completionInjected`) are in-memory only. A process restart resets them, which is accepted behavior: the completion review is a one-per-session post-task adaptation and a restart is treated as a fresh conversation boundary. The cadence state (`turnsSinceMemory` / `turnsSinceSkill`) is persisted via `ReviewState` and survives restart.
|
|
29
29
|
- `evolution/review-scheduled` and `evolution/review-error` are emitted for platform/user wiring only — this family has no in-repo production `ctx.on` consumer for them. They are declared externally owned (the platform side wires consumption), which matches the `EXEMPT_ORPHANS` set in `scripts/verify-event-pairing.mjs`.
|
|
30
30
|
- When the `evolution-state` service is not mounted, the memory/skill cadence state is not persisted and every turn restarts from a clean `{ turnsSinceMemory: 0, turnsSinceSkill: 0 }` baseline — the review schedule is stateless and re-decided each turn rather than accumulating across the conversation. The loss is surfaced once per process as a logger warning at the first turn/end.
|
|
31
|
+
- Read-before-write can see the review subagent's own `skill` reads only when the subagent backend exposes `localAgent` (the in-process driver does; out-of-process backends such as ACP and the CLI providers set `localAgent: undefined`). With a remote backend the subagent's reads are invisible, so a plan item patching a skill the subagent itself loaded is dropped as "unread" — the review then falls back to the parent session's reads only. Documented rather than worked around: recovering the child read set needs a `SubagentLike` contract change (v14 P2-6).
|
|
31
32
|
|
|
32
33
|
## Configuration
|
|
33
34
|
|
|
34
35
|
`reviewProvider` selects the LLM provider for review subagents. When omitted, the subagent inherits the deployment default route instead of a hardcoded provider name. Model selection stays on the policy (`memoryReviewModel` / `skillReviewModel`).
|
|
35
36
|
|
|
36
|
-
`reviewTimeoutMs` bounds each review subagent run (an `AbortSignal.timeout`; `0` aborts immediately). `executionTimeoutMs`
|
|
37
|
+
`reviewTimeoutMs` bounds each review subagent run (an `AbortSignal.timeout`; `0` aborts immediately). The former `executionTimeoutMs` declaration was removed in v14 (nothing read it, so it was configuration that did nothing); use `reviewTimeoutMs`.
|
|
37
38
|
|
|
38
39
|
### Review delivery contract (0.3.38-0.3.42)
|
|
39
40
|
|
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_MEMORY_INTERVAL, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_USER_CHAR_LIMIT, PROMPT_BUNDLE, SkillLibrary, advanceReview, clampedNumber, evolutionIoAdapter, foldTurn, redactSecrets, resolveOrigins, resolveSkillsRoot, reviewPrompt, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
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, evolutionIoAdapter, foldTurn, redactSecrets, resolveOrigins, 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
|
/**
|
|
@@ -16,10 +16,9 @@ const Config = z.object({
|
|
|
16
16
|
memoryInterval: z.number().min(1).default(DEFAULT_REVIEW_MEMORY_INTERVAL),
|
|
17
17
|
skillInterval: z.number().min(1).default(DEFAULT_REVIEW_SKILL_INTERVAL),
|
|
18
18
|
reviewToolAllow: z.array(z.string()).default(["skill"]),
|
|
19
|
-
reviewTimeoutMs: z.number().min(1).default(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
reviewMessageChars: z.number().min(1).default(2e3),
|
|
19
|
+
reviewTimeoutMs: z.number().min(1).default(DEFAULT_REVIEW_TIMEOUT_MS),
|
|
20
|
+
reviewContextMessages: z.number().min(1).default(DEFAULT_REVIEW_CONTEXT_MESSAGES),
|
|
21
|
+
reviewMessageChars: z.number().min(1).default(DEFAULT_REVIEW_MESSAGE_CHARS),
|
|
23
22
|
reviewMaxDepth: z.number().min(1).default(1),
|
|
24
23
|
reviewProvider: z.string(),
|
|
25
24
|
skillReviewTrigger: z.union([
|
|
@@ -49,7 +48,6 @@ const REVIEW_OUTPUT_SCHEMA = {
|
|
|
49
48
|
summary: { type: "string" }
|
|
50
49
|
}
|
|
51
50
|
};
|
|
52
|
-
let statelessReviewStateWarned = false;
|
|
53
51
|
function clampReviewConfig(rawConfig, ctx) {
|
|
54
52
|
const clamped = [];
|
|
55
53
|
const field = (name, value, fallback, min) => {
|
|
@@ -60,9 +58,9 @@ function clampReviewConfig(rawConfig, ctx) {
|
|
|
60
58
|
const config = Object.assign({}, rawConfig, {
|
|
61
59
|
memoryInterval: field("memoryInterval", rawConfig.memoryInterval, DEFAULT_REVIEW_MEMORY_INTERVAL, 1),
|
|
62
60
|
skillInterval: field("skillInterval", rawConfig.skillInterval, DEFAULT_REVIEW_SKILL_INTERVAL, 1),
|
|
63
|
-
reviewTimeoutMs: field("reviewTimeoutMs", rawConfig.reviewTimeoutMs,
|
|
64
|
-
reviewContextMessages: field("reviewContextMessages", rawConfig.reviewContextMessages,
|
|
65
|
-
reviewMessageChars: field("reviewMessageChars", rawConfig.reviewMessageChars,
|
|
61
|
+
reviewTimeoutMs: field("reviewTimeoutMs", rawConfig.reviewTimeoutMs, DEFAULT_REVIEW_TIMEOUT_MS, 1),
|
|
62
|
+
reviewContextMessages: field("reviewContextMessages", rawConfig.reviewContextMessages, DEFAULT_REVIEW_CONTEXT_MESSAGES, 1),
|
|
63
|
+
reviewMessageChars: field("reviewMessageChars", rawConfig.reviewMessageChars, DEFAULT_REVIEW_MESSAGE_CHARS, 1),
|
|
66
64
|
reviewMaxDepth: field("reviewMaxDepth", rawConfig.reviewMaxDepth, 1, 1),
|
|
67
65
|
skillReviewCompletionMinToolCalls: field("skillReviewCompletionMinToolCalls", rawConfig.skillReviewCompletionMinToolCalls, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, 1)
|
|
68
66
|
});
|
|
@@ -73,6 +71,7 @@ function apply(ctx, rawConfig) {
|
|
|
73
71
|
if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to schedule review work");
|
|
74
72
|
const config = clampReviewConfig(rawConfig, ctx);
|
|
75
73
|
const turnStarts = /* @__PURE__ */ new Map();
|
|
74
|
+
let statelessReviewStateWarned = false;
|
|
76
75
|
const cumulativeToolCalls = /* @__PURE__ */ new Map();
|
|
77
76
|
const completionInjected = /* @__PURE__ */ new Set();
|
|
78
77
|
const pendingCadenceReviews = /* @__PURE__ */ new Map();
|
|
@@ -349,7 +348,11 @@ function apply(ctx, rawConfig) {
|
|
|
349
348
|
let ok = true;
|
|
350
349
|
try {
|
|
351
350
|
for (const op of plan.memoryOps ?? []) {
|
|
352
|
-
if (!Array.isArray(op.evidence) || op.evidence.length === 0)
|
|
351
|
+
if (!Array.isArray(op.evidence) || op.evidence.length === 0) {
|
|
352
|
+
ok = false;
|
|
353
|
+
failedOps.push(`memory ${op.action ?? "add"} ${op.target}: missing evidence (defense-in-depth rejection)`);
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
353
356
|
const normalized = {
|
|
354
357
|
target: op.target === "user" ? "user" : "memory",
|
|
355
358
|
action: op.action ?? "add",
|
|
@@ -364,7 +367,11 @@ function apply(ctx, rawConfig) {
|
|
|
364
367
|
}
|
|
365
368
|
}
|
|
366
369
|
for (const op of plan.skillOps ?? []) {
|
|
367
|
-
if (!Array.isArray(op.evidence) || op.evidence.length === 0 || !op.name)
|
|
370
|
+
if (!Array.isArray(op.evidence) || op.evidence.length === 0 || !op.name) {
|
|
371
|
+
ok = false;
|
|
372
|
+
failedOps.push(`skill ${op.action ?? "patch"} ${op.name ?? "<unnamed>"}: missing evidence or name (defense-in-depth rejection)`);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
368
375
|
const args = {
|
|
369
376
|
...op,
|
|
370
377
|
evidence: op.evidence
|
|
@@ -472,7 +479,7 @@ function apply(ctx, rawConfig) {
|
|
|
472
479
|
if (archived.ok) await ctx.get("skillUsage")?.markArchived?.(name);
|
|
473
480
|
return archived;
|
|
474
481
|
}
|
|
475
|
-
if (op.action === "write_file") return await library.writeSupportFile(name, op.file_path ?? "", op.file_content ??
|
|
482
|
+
if (op.action === "write_file") return await library.writeSupportFile(name, op.file_path ?? "", op.file_content ?? "", origin);
|
|
476
483
|
if (op.action === "remove_file") return await library.removeSupportFile(name, op.file_path ?? "", origin);
|
|
477
484
|
if (op.action === "restructure") {
|
|
478
485
|
const moves = (op.restructure ?? []).filter((move) => move !== null).map((move) => ({
|
package/lib/types/index.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ export interface Config {
|
|
|
18
18
|
*/
|
|
19
19
|
reviewToolAllow?: string[];
|
|
20
20
|
reviewTimeoutMs?: number;
|
|
21
|
-
executionTimeoutMs?: number;
|
|
22
21
|
reviewContextMessages?: number;
|
|
23
22
|
reviewMessageChars?: number;
|
|
24
23
|
/** ABSOLUTE cap of the review subagent's own delegation depth (platform
|
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.63",
|
|
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.63",
|
|
35
|
+
"@lmzhen/dsh-evolution-core": "^0.3.63",
|
|
36
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.3.63"
|
|
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.63",
|
|
46
|
+
"@lmzhen/dsh-evolution-policy": "^0.3.63"
|
|
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.63",
|
|
58
|
+
"@lmzhen/dsh-evolution-core": "^0.3.63",
|
|
59
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.3.63",
|
|
60
|
+
"@lmzhen/dsh-evolution-state": "^0.3.63"
|
|
61
61
|
}
|
|
62
62
|
}
|