@lmzhen/dsh-evolution-review 0.30.23 → 0.30.25
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 +31 -9
- package/lib/types/index.d.ts +13 -1
- package/package.json +11 -11
package/lib/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
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, authorityFrom, clampOnce, classifySessionEvent, clearReviewChannel, contentHash, createSubagentChannel, evolutionIoAdapter, filterUnreadSkillOps, filterUnreadSkillOps as filterUnreadSkillOps$1, foldUntrustedLines, isPresent, isUnknown, liveBool, markReviewChannel, newSkillLibrary, paramRowId, payloadText, pickWithPolicy, policyStageLimits, readDispatchSignal, redactSecrets, resolveOrigins, resolveRootConfig, reviewPrompt, sessionAudited, sessionEvidenceIndex, sessionReadNames, sessionTurnSignals, sweepReviewChannelSessions, unwrapLive, userSetKeys, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
1
|
+
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, authorityFrom, clampOnce, classifySessionEvent, clearReviewChannel, contentHash, createSubagentChannel, ensureSkillFrontmatter, evolutionIoAdapter, filterUnreadSkillOps, filterUnreadSkillOps as filterUnreadSkillOps$1, foldUntrustedLines, isPresent, isUnknown, liveBool, markReviewChannel, newSkillLibrary, paramRowId, payloadText, pickWithPolicy, policyStageLimits, readDispatchSignal, redactSecrets, resolveOrigins, resolveRootConfig, reviewPrompt, sessionAudited, sessionEvidenceIndex, sessionReadNames, sessionTurnSignals, sweepReviewChannelSessions, unwrapLive, userSetKeys, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
5
5
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
6
|
-
import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
|
|
6
|
+
import { planContractPrompt, 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.
|
|
9
9
|
*
|
|
@@ -143,6 +143,10 @@ function emitReviewScheduled(ctx, event) {
|
|
|
143
143
|
/** Error name marking the S2-6 watchdog expiry (see the catch in trySubagentReview). */
|
|
144
144
|
const name = "evolution-review";
|
|
145
145
|
const inject = ["agents"];
|
|
146
|
+
/** Result notices are optional; a review PROMPT is the review itself in inject mode. */
|
|
147
|
+
function noticeAllowed(reviewPrompt, notice) {
|
|
148
|
+
return reviewPrompt || notice;
|
|
149
|
+
}
|
|
146
150
|
const Config = z.object({
|
|
147
151
|
reviewEnabled: z.boolean().default(true).volatile(),
|
|
148
152
|
reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("inject").volatile(),
|
|
@@ -162,6 +166,7 @@ const Config = z.object({
|
|
|
162
166
|
z.const("both")
|
|
163
167
|
]).default(DEFAULT_SKILL_REVIEW_TRIGGER).volatile(),
|
|
164
168
|
reviewWakeInject: z.boolean().default(true).volatile(),
|
|
169
|
+
reviewNotice: z.boolean().default(true).volatile(),
|
|
165
170
|
sessionScoped: z.boolean().default(false),
|
|
166
171
|
skillReviewCompletionMinToolCalls: z.number().min(1).default(DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS).volatile(),
|
|
167
172
|
root: z.string().default(""),
|
|
@@ -235,7 +240,8 @@ function resolveReviewRowSettings(rawConfig, warn) {
|
|
|
235
240
|
skillReviewCompletionMinToolCalls: clampOnce(warned, warn, "skillReviewCompletionMinToolCalls", rawConfig.skillReviewCompletionMinToolCalls, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, 1),
|
|
236
241
|
reviewEnabled: liveBool(rawConfig.reviewEnabled, true),
|
|
237
242
|
reviewMode: unwrapLive(rawConfig.reviewMode) ?? "inject",
|
|
238
|
-
reviewWakeInject: liveBool(rawConfig.reviewWakeInject, true)
|
|
243
|
+
reviewWakeInject: liveBool(rawConfig.reviewWakeInject, true),
|
|
244
|
+
reviewNotice: liveBool(rawConfig.reviewNotice, true)
|
|
239
245
|
};
|
|
240
246
|
}
|
|
241
247
|
function apply(ctx, rawConfig = {}) {
|
|
@@ -289,7 +295,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
289
295
|
skillReviewCompletionMinToolCalls: row.skillReviewCompletionMinToolCalls,
|
|
290
296
|
reviewEnabled: row.reviewEnabled,
|
|
291
297
|
reviewMode: mode(),
|
|
292
|
-
reviewWakeInject: row.reviewWakeInject
|
|
298
|
+
reviewWakeInject: row.reviewWakeInject,
|
|
299
|
+
reviewNotice: row.reviewNotice
|
|
293
300
|
};
|
|
294
301
|
};
|
|
295
302
|
const schemaDefaults = Config["~standard"].validate({}).value;
|
|
@@ -639,6 +646,10 @@ function apply(ctx, rawConfig = {}) {
|
|
|
639
646
|
const deliverMessage = (agent, text, summary, reviewPrompt = false) => {
|
|
640
647
|
const wake = agent;
|
|
641
648
|
const inbox = agent.inbox;
|
|
649
|
+
if (!noticeAllowed(reviewPrompt, params().reviewNotice)) {
|
|
650
|
+
ctx.logger.info(`dsh-evolution-review: suppressed a result notice (${summary}) — reviewNotice is off`);
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
642
653
|
if (reviewPrompt && noticeIsOutstanding(agent.session.id, inbox)) {
|
|
643
654
|
if (!reviewNoticeOutstandingWarned) {
|
|
644
655
|
reviewNoticeOutstandingWarned = true;
|
|
@@ -982,6 +993,13 @@ function apply(ctx, rawConfig = {}) {
|
|
|
982
993
|
...op,
|
|
983
994
|
evidence: op.evidence
|
|
984
995
|
};
|
|
996
|
+
if ((args.action === "create" || args.action === "edit" || args.action === "update") && typeof args.content === "string" && typeof args.name === "string") {
|
|
997
|
+
const repaired = ensureSkillFrontmatter(args.content, args.name, args.description);
|
|
998
|
+
if (repaired.repaired) {
|
|
999
|
+
args.content = repaired.content;
|
|
1000
|
+
ctx.logger.warn(`dsh-evolution-review: synthesized missing SKILL.md frontmatter for ${args.name}`);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
985
1003
|
let stagedBytes;
|
|
986
1004
|
if ((args.action === "update" || args.action === "edit") && hashLibrary && typeof args.name === "string" && args.name !== "") {
|
|
987
1005
|
const probe = await hashLibrary.readSkillProbe(args.name);
|
|
@@ -1256,6 +1274,7 @@ function appendDispatchFrame(digest, id, event) {
|
|
|
1256
1274
|
const frames = digest.get(id) ?? [];
|
|
1257
1275
|
frames.push({
|
|
1258
1276
|
type: event.type,
|
|
1277
|
+
...event.seq === void 0 ? {} : { seq: event.seq },
|
|
1259
1278
|
...event.data === void 0 ? {} : { data: event.data }
|
|
1260
1279
|
});
|
|
1261
1280
|
if (frames.length > DISPATCH_DIGEST_FRAMES) frames.splice(0, frames.length - DISPATCH_DIGEST_FRAMES);
|
|
@@ -1321,7 +1340,7 @@ function resultCallIdOf(event) {
|
|
|
1321
1340
|
* keeps the call identity its `[call]` line would have had. Budget: 500 chars
|
|
1322
1341
|
* per line (the 12-line cap lives in buildReviewRequest and is unchanged).
|
|
1323
1342
|
*/
|
|
1324
|
-
function renderToolResultLine(data, identity) {
|
|
1343
|
+
function renderToolResultLine(data, identity, seq) {
|
|
1325
1344
|
const shape = data;
|
|
1326
1345
|
const nativeContent = shape?.message?.content;
|
|
1327
1346
|
const resultBlocks = Array.isArray(nativeContent) ? nativeContent.filter((block) => block.type === "tool-result") : [];
|
|
@@ -1338,7 +1357,8 @@ function renderToolResultLine(data, identity) {
|
|
|
1338
1357
|
failed = false;
|
|
1339
1358
|
}
|
|
1340
1359
|
const head = identity === void 0 ? "" : `${foldUntrustedLines(identity.name, 0)} ${foldUntrustedLines(identity.argsRaw, 200)} → `;
|
|
1341
|
-
|
|
1360
|
+
const failure = failed ? " [ERROR]" : "";
|
|
1361
|
+
return (seq === void 0 ? "" : "seq=" + String(seq) + " ") + "[result]" + failure + " " + head + foldUntrustedLines(output, 500);
|
|
1342
1362
|
}
|
|
1343
1363
|
/** Text of a PTC settle `content` payload (the logged ContentBlock list):
|
|
1344
1364
|
* text blocks and plain strings joined, anything else skipped. */
|
|
@@ -1402,14 +1422,15 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars,
|
|
|
1402
1422
|
name: settleData.name,
|
|
1403
1423
|
argsRaw: typeof settleData.arguments === "string" ? settleData.arguments : JSON.stringify(settleData.arguments ?? {})
|
|
1404
1424
|
} : callIdentity.get(answeredCallId);
|
|
1405
|
-
toolLines.push(renderToolResultLine(event?.data, identity));
|
|
1425
|
+
toolLines.push(renderToolResultLine(event?.data, identity, event?.seq));
|
|
1406
1426
|
continue;
|
|
1407
1427
|
}
|
|
1408
1428
|
const opened = readDispatchSignal(event);
|
|
1409
1429
|
if (opened === null || openedCallIds.has(opened.callId)) continue;
|
|
1410
1430
|
openedCallIds.add(opened.callId);
|
|
1411
1431
|
const argsRaw = typeof opened.arguments === "string" ? opened.arguments : JSON.stringify(opened.arguments ?? {});
|
|
1412
|
-
|
|
1432
|
+
const seq = typeof event?.seq === "number" ? "seq=" + String(event.seq) + " " : "";
|
|
1433
|
+
toolLines.push(seq + "[call] " + foldUntrustedLines(opened.name, 0) + " " + foldUntrustedLines(argsRaw, 500));
|
|
1413
1434
|
}
|
|
1414
1435
|
toolLines.reverse();
|
|
1415
1436
|
return [
|
|
@@ -1418,9 +1439,10 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars,
|
|
|
1418
1439
|
`Recent tool activity (${toolLines.length}):`,
|
|
1419
1440
|
...toolLines,
|
|
1420
1441
|
"Return ONLY the structured JSON plan. Evidence is mandatory for every op.",
|
|
1442
|
+
planContractPrompt(),
|
|
1421
1443
|
"",
|
|
1422
1444
|
...messages
|
|
1423
1445
|
].join("\n");
|
|
1424
1446
|
}
|
|
1425
1447
|
//#endregion
|
|
1426
|
-
export { Config, REVIEW_OUTPUT_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, renderToolResultLine, resolveReviewRowSettings, shouldCompletionReview, sweepDeadSessionEntries };
|
|
1448
|
+
export { Config, REVIEW_OUTPUT_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, noticeAllowed, renderToolResultLine, resolveReviewRowSettings, shouldCompletionReview, sweepDeadSessionEntries };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export { filterUnreadSkillOps } from '@lmzhen/dsh-evolution-core';
|
|
|
25
25
|
/** Error name marking the S2-6 watchdog expiry (see the catch in trySubagentReview). */
|
|
26
26
|
export declare const name = "evolution-review";
|
|
27
27
|
export declare const inject: string[];
|
|
28
|
+
/** Result notices are optional; a review PROMPT is the review itself in inject mode. */
|
|
29
|
+
export declare function noticeAllowed(reviewPrompt: boolean, notice: boolean): boolean;
|
|
28
30
|
export interface Config {
|
|
29
31
|
reviewEnabled?: Volatile<boolean>;
|
|
30
32
|
/** How the flush delivers the review: `'inject'` (default since 0.3.74) hands
|
|
@@ -85,6 +87,10 @@ export interface Config {
|
|
|
85
87
|
* differs). Default true; false degrades to the non-waking inject (the
|
|
86
88
|
* summary then waits for the next driver wake). */
|
|
87
89
|
reviewWakeInject?: Volatile<boolean>;
|
|
90
|
+
/** Deliver result notices into the parent conversation. Default true. A review PROMPT is the
|
|
91
|
+
* review itself in inject mode, so this never suppresses prompt delivery — only the result
|
|
92
|
+
* notice (and late/zero-landing notices) that wakes a turn just to report a count. */
|
|
93
|
+
reviewNotice?: Volatile<boolean>;
|
|
88
94
|
/** V10-11 (P2-7): skill tree root for the review's direct skill writes.
|
|
89
95
|
* Empty (the default) resolves through `resolveSkillsRoot` to the shared
|
|
90
96
|
* default root — the historical behavior. A custom root keeps review-created
|
|
@@ -119,6 +125,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
119
125
|
reviewProvider: z<string, string, "plain">;
|
|
120
126
|
skillReviewTrigger: z<"cadence" | "completion" | "both", "cadence" | "completion" | "both", "volatile-defined">;
|
|
121
127
|
reviewWakeInject: z<boolean, boolean, "volatile-defined">;
|
|
128
|
+
reviewNotice: z<boolean, boolean, "volatile-defined">;
|
|
122
129
|
sessionScoped: z<boolean, boolean, "defined">;
|
|
123
130
|
skillReviewCompletionMinToolCalls: z<number, number, "volatile-defined">;
|
|
124
131
|
root: z<string, string, "defined">;
|
|
@@ -138,6 +145,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
138
145
|
reviewProvider: z<string, string, "plain">;
|
|
139
146
|
skillReviewTrigger: z<"cadence" | "completion" | "both", "cadence" | "completion" | "both", "volatile-defined">;
|
|
140
147
|
reviewWakeInject: z<boolean, boolean, "volatile-defined">;
|
|
148
|
+
reviewNotice: z<boolean, boolean, "volatile-defined">;
|
|
141
149
|
sessionScoped: z<boolean, boolean, "defined">;
|
|
142
150
|
skillReviewCompletionMinToolCalls: z<number, number, "volatile-defined">;
|
|
143
151
|
root: z<string, string, "defined">;
|
|
@@ -208,6 +216,8 @@ export interface ReviewSettings {
|
|
|
208
216
|
reviewMode: 'subagent' | 'inject';
|
|
209
217
|
/** Deliver the deferred review as a waking follow-up message. */
|
|
210
218
|
reviewWakeInject: boolean;
|
|
219
|
+
/** Deliver result notices (not review prompts). */
|
|
220
|
+
reviewNotice: boolean;
|
|
211
221
|
}
|
|
212
222
|
/**
|
|
213
223
|
* This row's review knobs as they stand RIGHT NOW (G1 §8.3) — the base layer of the
|
|
@@ -228,6 +238,8 @@ export declare function shouldCompletionReview(reason: {
|
|
|
228
238
|
/** One dispatch frame the review digest can render (a native call/result or a PTC sub-dispatch). */
|
|
229
239
|
interface ReviewDispatchFrame {
|
|
230
240
|
readonly type: string;
|
|
241
|
+
/** Session seq of the frame, so a plan can cite a real `event_seq`. */
|
|
242
|
+
readonly seq?: number;
|
|
231
243
|
readonly data?: unknown;
|
|
232
244
|
}
|
|
233
245
|
/**
|
|
@@ -260,7 +272,7 @@ export declare function sweepDeadSessionEntries<K>(entries: Map<K, unknown> | Se
|
|
|
260
272
|
export declare function renderToolResultLine(data: unknown, identity?: {
|
|
261
273
|
name: string;
|
|
262
274
|
argsRaw: string;
|
|
263
|
-
}): string;
|
|
275
|
+
}, seq?: number): string;
|
|
264
276
|
export declare function buildReviewRequest(session: Session, kind: ReviewKind, signal: {
|
|
265
277
|
toolCalls: number;
|
|
266
278
|
userChars: number;
|
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.30.
|
|
4
|
+
"version": "0.30.25",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.30.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.30.
|
|
32
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.30.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.30.25",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.30.25",
|
|
32
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.30.25"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@deepseek-ai/cordis": "^4.0.5",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"@deepseek-ai/dsh-llm": "^0.2.1-rc.1",
|
|
38
38
|
"@deepseek-ai/dsh-session": "^0.2.1-rc.1",
|
|
39
39
|
"@deepseek-ai/dsh-tools": "^0.2.1-rc.1",
|
|
40
|
-
"@lmzhen/dsh-evolution-policy": "^0.30.
|
|
41
|
-
"@lmzhen/dsh-evolution-state": "^0.30.
|
|
40
|
+
"@lmzhen/dsh-evolution-policy": "^0.30.25",
|
|
41
|
+
"@lmzhen/dsh-evolution-state": "^0.30.25"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@deepseek-ai/dsh-agent": "^0.2.1-rc.1",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"@deepseek-ai/dsh-session-persistence": "^0.2.1-rc.1",
|
|
49
49
|
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.2.1-rc.1",
|
|
50
50
|
"@deepseek-ai/dsh-tools": "^0.2.1-rc.1",
|
|
51
|
-
"@lmzhen/dsh-evolution-approval": "^0.30.
|
|
52
|
-
"@lmzhen/dsh-evolution-core": "^0.30.
|
|
53
|
-
"@lmzhen/dsh-evolution-curator": "^0.30.
|
|
54
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.30.
|
|
55
|
-
"@lmzhen/dsh-evolution-state": "^0.30.
|
|
51
|
+
"@lmzhen/dsh-evolution-approval": "^0.30.25",
|
|
52
|
+
"@lmzhen/dsh-evolution-core": "^0.30.25",
|
|
53
|
+
"@lmzhen/dsh-evolution-curator": "^0.30.25",
|
|
54
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.30.25",
|
|
55
|
+
"@lmzhen/dsh-evolution-state": "^0.30.25"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
58
58
|
"dsh": ">=0.2.1-rc.1 <0.2.2-0"
|