@lmzhen/dsh-evolution-review 0.1.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/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @deepseek-ai/dsh-evolution-review
2
+
3
+ Background review orchestration
4
+
5
+ ## Model Experience
6
+
7
+ ### Indirect model surface
8
+
9
+ #### What the model sees
10
+
11
+ `@deepseek-ai/dsh-evolution-review` registers no direct prompt or tool schema itself. Model-visible effects are owned by the packages that consume this service.
12
+
13
+ #### Token effect
14
+
15
+ Zero direct token effect from this package; consumers add any model-visible tokens.
16
+
17
+ #### KV Cache effect
18
+
19
+ Independent of request-prefix construction. This package does not alter the assembled prompt or tool list.
20
+
21
+ ## Known Limitations and Deferred Work
22
+
23
+
24
+ - - Review subagents inherit the host preset; Anchored Standard deployments rely on the default `skill_search`/`skill_load` allow-list.
package/lib/index.js ADDED
@@ -0,0 +1,239 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import z from "@deepseek-ai/schemastery";
3
+ import { CallId, createUserMessage } from "@deepseek-ai/dsh-llm";
4
+ import { PROMPT_BUNDLE, advanceReview, foldTurn, reviewPrompt, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
5
+ import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
6
+ //#region lib/types/index.js
7
+ /**
8
+ * Background review orchestration: signal gate → one-shot subagent → trusted plan execution.
9
+ * @module @lmzhen/dsh-evolution-review
10
+ */
11
+ const name = "evolution-review";
12
+ const inject = ["agents", "tools"];
13
+ const Config = z.object({
14
+ reviewEnabled: z.boolean().default(true),
15
+ reviewMode: z.string().default("subagent"),
16
+ memoryInterval: z.number().default(10),
17
+ skillInterval: z.number().default(10),
18
+ reviewToolAllow: z.array(z.string()).default([
19
+ "skill",
20
+ "skill_search",
21
+ "skill_load"
22
+ ]),
23
+ reviewTimeoutMs: z.number().default(12e4),
24
+ executionTimeoutMs: z.number().default(3e4),
25
+ reviewContextMessages: z.number().default(60),
26
+ reviewMessageChars: z.number().default(2e3),
27
+ reviewMaxDepth: z.number().default(0)
28
+ });
29
+ function apply(ctx, rawConfig) {
30
+ if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to schedule review work");
31
+ const config = rawConfig;
32
+ const turnStarts = /* @__PURE__ */ new Map();
33
+ const policy = () => ctx.get("evolutionPolicy")?.get();
34
+ ctx.on("session/event", (session, event) => {
35
+ if (event.type === "turn/start") turnStarts.set(session.id, session.seq - 1);
36
+ if (event.type !== "turn/end") return;
37
+ onTurnEnd(session, event);
38
+ });
39
+ async function onTurnEnd(session, event) {
40
+ if (!config.reviewEnabled) return;
41
+ if (session.header.origin === "subagent") return;
42
+ const agent = ctx.agents.get(session.id);
43
+ if (!agent) return;
44
+ const signal = foldTurn(session, turnStarts.get(session.id) ?? Math.max(0, session.seq - 1));
45
+ turnStarts.delete(session.id);
46
+ const stateService = ctx.get("evolutionState");
47
+ const state = await stateService?.loadReviewState(session.id) ?? {
48
+ turnsSinceMemory: 0,
49
+ turnsSinceSkill: 0,
50
+ lastTurn: -1
51
+ };
52
+ const snapshot = policy();
53
+ const kind = advanceReview(state, event.data.turn, signal, {
54
+ memoryInterval: snapshot?.reviewMemoryInterval ?? config.memoryInterval,
55
+ skillInterval: snapshot?.reviewSkillInterval ?? config.skillInterval,
56
+ substantiveMinToolCalls: snapshot?.substantiveMinToolCalls ?? 3,
57
+ substantiveMinUserChars: snapshot?.substantiveMinUserChars ?? 200,
58
+ substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ?? 500
59
+ });
60
+ await stateService?.saveReviewState(session.id, state);
61
+ if (!kind) return;
62
+ if (!await trySubagentReview(session, agent, kind, signal)) agent.inject(createUserMessage({
63
+ content: [{
64
+ type: "text",
65
+ text: reviewPrompt(kind)
66
+ }],
67
+ source: {
68
+ kind: "plugin",
69
+ plugin: "dsh-evolution-review",
70
+ form: "notice",
71
+ summary: "auto-review"
72
+ }
73
+ }));
74
+ }
75
+ async function trySubagentReview(session, agent, kind, signal) {
76
+ if ((policy()?.reviewMode ?? config.reviewMode) === "inject") return false;
77
+ const subagents = ctx.get("subagents");
78
+ if (!subagents) return false;
79
+ try {
80
+ const routingPolicy = ctx.get("evolutionPolicy");
81
+ const model = kind === "memory" ? routingPolicy?.get().memoryReviewModel ?? "deepseek-v4-flash" : routingPolicy?.get().skillReviewModel ?? "deepseek-v4-pro";
82
+ const reviewText = buildReviewRequest(session, kind, signal, config.reviewContextMessages, config.reviewMessageChars);
83
+ const run = await subagents.start("spawn", {
84
+ label: "dsh-evolution-review",
85
+ prompt: [{
86
+ type: "text",
87
+ text: reviewText
88
+ }],
89
+ parent: agent,
90
+ signal: AbortSignal.timeout(config.reviewTimeoutMs),
91
+ maxDepth: config.reviewMaxDepth,
92
+ agentOptions: {
93
+ provider: "deepseek-official",
94
+ model
95
+ },
96
+ persona: reviewPrompt(kind),
97
+ toolFilter: { allow: [...config.reviewToolAllow] },
98
+ outputSchema: {
99
+ type: "object",
100
+ additionalProperties: false,
101
+ properties: {
102
+ memoryOps: {
103
+ type: "array",
104
+ items: { type: "json" }
105
+ },
106
+ skillOps: {
107
+ type: "array",
108
+ items: { type: "json" }
109
+ },
110
+ summary: { type: "string" }
111
+ }
112
+ }
113
+ });
114
+ const result = await run.result;
115
+ await run.dispose();
116
+ if (!result.structured) return true;
117
+ const snapshot = policy();
118
+ const plan = result.structured;
119
+ const policyFingerprint = fingerprintPolicy(snapshot);
120
+ const validation = validateEvolutionPlan(plan, {
121
+ sessionSeq: session.seq - 1,
122
+ maxOpsPerPlan: snapshot?.maxOpsPerPlan ?? 32,
123
+ protectedSkillNames: new Set(snapshot?.protectedSkillNames ?? []),
124
+ maxMemoryChars: snapshot?.memoryChars ?? 2200,
125
+ maxUserChars: snapshot?.userChars ?? 1375,
126
+ maxSkillContentChars: snapshot?.skillContentChars ?? 1e5
127
+ });
128
+ const actions = await executePlan(validation.accepted, agent);
129
+ const evidenceQuotes = [...validation.accepted.memoryOps ?? [], ...validation.accepted.skillOps ?? []].reduce((total, op) => total + (Array.isArray(op.evidence) ? op.evidence.length : 0), 0);
130
+ session.append("evolution/plan-applied", {
131
+ planId: randomUUID(),
132
+ policyFingerprint,
133
+ memoryApplied: actions.filter((action) => action.startsWith("Memory")).length,
134
+ skillApplied: actions.filter((action) => action.startsWith("Skill ")).length,
135
+ rejectedOps: validation.rejected.length,
136
+ evidenceQuotes,
137
+ estimatedInputChars: reviewText.length
138
+ });
139
+ if (actions.length > 0) agent.inject(createUserMessage({
140
+ content: [{
141
+ type: "text",
142
+ text: `💾 Self-improvement review: ${actions.join(" · ")}`
143
+ }],
144
+ source: {
145
+ kind: "plugin",
146
+ plugin: "dsh-evolution-review",
147
+ form: "notice",
148
+ summary: "self-improvement review"
149
+ }
150
+ }));
151
+ return true;
152
+ } catch {
153
+ return false;
154
+ }
155
+ }
156
+ async function executePlan(plan, parent) {
157
+ const memory = ctx.get("memory");
158
+ const approval = ctx.get("evolutionApproval");
159
+ const actions = [];
160
+ for (const op of plan.memoryOps ?? []) {
161
+ if (!Array.isArray(op.evidence) || op.evidence.length === 0) continue;
162
+ const normalized = {
163
+ target: op.target === "user" ? "user" : "memory",
164
+ action: op.action ?? "add",
165
+ facts: op.facts ?? op.content,
166
+ old_text: op.old_text
167
+ };
168
+ if ((approval ? await runApproved("memory", `memory ${normalized.target} ${normalized.action}`, normalized, normalized) : await memory?.applyBatch(normalized.target, [normalized]))?.ok) actions.push("Memory updated");
169
+ }
170
+ for (const op of plan.skillOps ?? []) {
171
+ if (!Array.isArray(op.evidence) || op.evidence.length === 0 || !op.name) continue;
172
+ const args = {
173
+ ...op,
174
+ evidence: op.evidence
175
+ };
176
+ if ((approval ? await runApproved("skill", `skill ${op.action ?? "patch"} ${op.name}`, {
177
+ operation: args,
178
+ origin: "background_review"
179
+ }, args) : await executeSkillTool(parent, args))?.ok) actions.push(`Skill ${op.name} ${op.action ?? "patch"}`);
180
+ }
181
+ return actions;
182
+ async function runApproved(kind, summary, stored, runnerArgs) {
183
+ if (!approval) return void 0;
184
+ const decision = await approval.request({
185
+ kind,
186
+ summary,
187
+ args: stored,
188
+ origin: "background_review"
189
+ });
190
+ if (decision.action === "staged") return {
191
+ ok: false,
192
+ message: decision.message
193
+ };
194
+ return await approval.run(kind, runnerArgs);
195
+ }
196
+ async function executeSkillTool(agent, args) {
197
+ return (await ctx.tools.execute({
198
+ callId: CallId(`evolution-${randomUUID()}`),
199
+ name: "skill_manage",
200
+ arguments: args,
201
+ agent,
202
+ signal: AbortSignal.timeout(config.executionTimeoutMs)
203
+ })).isError ? {
204
+ ok: false,
205
+ message: "skill_manage execution failed"
206
+ } : {
207
+ ok: true,
208
+ message: "skill_manage executed"
209
+ };
210
+ }
211
+ }
212
+ ctx.effect(() => () => {
213
+ turnStarts.clear();
214
+ }, "dsh-evolution-review.cleanup");
215
+ }
216
+ function fingerprintPolicy(snapshot) {
217
+ try {
218
+ return createHash("sha256").update(JSON.stringify(snapshot)).digest("hex").slice(0, 12);
219
+ } catch {
220
+ return;
221
+ }
222
+ }
223
+ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars) {
224
+ const messages = [];
225
+ const surface = session.deriveMessages();
226
+ for (const message of surface.slice(-maxMessages)) if (message.role === "user" || message.role === "assistant") {
227
+ const text = message.content.map((block) => block.type === "text" ? block.text : "").join(" ").trim();
228
+ if (text) messages.push(`${message.role.toUpperCase()}: ${text.slice(0, maxMessageChars)}`);
229
+ }
230
+ return [
231
+ `Review kind: ${kind}`,
232
+ `Signals: ${signal.toolCalls} tool calls, ${signal.userChars} user chars, ${signal.assistantChars} assistant chars.`,
233
+ "Return ONLY the structured JSON plan. Evidence is mandatory for every op.",
234
+ "",
235
+ ...messages
236
+ ].join("\n");
237
+ }
238
+ //#endregion
239
+ export { Config, apply, inject, name };
@@ -0,0 +1,8 @@
1
+ //#region lib/types/invariant.js
2
+ const PACKAGE_NAME = "@deepseek-ai/dsh-evolution-review";
3
+ const name = "evolution-review-invariant";
4
+ const inject = ["invariants"];
5
+ const install = () => {};
6
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
7
+ //#endregion
8
+ export { apply, inject, name };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Background review orchestration: signal gate → one-shot subagent → trusted plan execution.
3
+ * @module @deepseek-ai/dsh-evolution-review
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ import z from '@deepseek-ai/schemastery';
7
+ export declare const name = "evolution-review";
8
+ export declare const inject: string[];
9
+ export interface Config {
10
+ reviewEnabled?: boolean;
11
+ reviewMode?: string;
12
+ memoryInterval?: number;
13
+ skillInterval?: number;
14
+ /** Tools the one-shot review subagent may use. Defaults include the Anchored Standard discovery pair. */
15
+ reviewToolAllow?: string[];
16
+ reviewTimeoutMs?: number;
17
+ executionTimeoutMs?: number;
18
+ reviewContextMessages?: number;
19
+ reviewMessageChars?: number;
20
+ reviewMaxDepth?: number;
21
+ }
22
+ export declare const Config: z<Config>;
23
+ export declare function apply(ctx: Context, rawConfig: Config): void;
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ export declare const name = "evolution-review-invariant";
3
+ export declare const inject: string[];
4
+ export declare const apply: (ctx: Context) => Promise<() => void>;
5
+ //# sourceMappingURL=invariant.d.ts.map
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@lmzhen/dsh-evolution-review",
3
+ "description": "Background review orchestration (community build)",
4
+ "version": "0.1.0-rc.1",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/lmzhen/dsh-evolution.git",
11
+ "directory": "packages/dsh-evolution-review"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "lib/index.js",
29
+ "lib/invariant.js",
30
+ "lib/types/**/*.d.ts",
31
+ "lib/types/invariant.d.ts"
32
+ ],
33
+ "license": "MIT",
34
+ "dependencies": {
35
+ "@deepseek-ai/schemastery": "^3.18.1",
36
+ "@lmzhen/dsh-evolution-core": "^0.1.0-rc.1"
37
+ },
38
+ "peerDependencies": {
39
+ "@deepseek-ai/cordis": "^4.0.1",
40
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
41
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
42
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
43
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
44
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
45
+ "@lmzhen/dsh-evolution-plan-validator": "^0.1.0-rc.1",
46
+ "@lmzhen/dsh-evolution-state": "^0.1.0-rc.1"
47
+ },
48
+ "devDependencies": {
49
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
50
+ "@deepseek-ai/dsh-agent-loop-testkit": "^0.1.0-rc.6",
51
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
52
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
53
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
54
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
55
+ "@lmzhen/dsh-evolution-core": "^0.1.0-rc.1",
56
+ "@lmzhen/dsh-evolution-plan-validator": "^0.1.0-rc.1",
57
+ "@lmzhen/dsh-evolution-state": "^0.1.0-rc.1"
58
+ }
59
+ }