@lmzhen/dsh-evolution-review 0.1.0-rc.42 → 0.1.0-rc.43
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 +72 -43
- package/lib/types/index.d.ts +10 -0
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -64,6 +64,12 @@ function apply(ctx, rawConfig) {
|
|
|
64
64
|
ctx.on("session/event", (session, event) => {
|
|
65
65
|
if (event.type === "turn/start") turnStarts.set(session.id, session.seq - 1);
|
|
66
66
|
if (event.type !== "turn/end") return;
|
|
67
|
+
if (turnStarts.size >= 128 || cumulativeToolCalls.size >= 128 || completionInjected.size >= 128) {
|
|
68
|
+
const isAlive = (id) => ctx.agents.get(id) !== void 0;
|
|
69
|
+
sweepDeadSessionEntries(turnStarts, isAlive);
|
|
70
|
+
sweepDeadSessionEntries(cumulativeToolCalls, isAlive);
|
|
71
|
+
sweepDeadSessionEntries(completionInjected, isAlive);
|
|
72
|
+
}
|
|
67
73
|
onTurnEnd(session, event);
|
|
68
74
|
});
|
|
69
75
|
async function onTurnEnd(session, event) {
|
|
@@ -175,49 +181,55 @@ function apply(ctx, rawConfig) {
|
|
|
175
181
|
}
|
|
176
182
|
}
|
|
177
183
|
});
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
184
|
+
try {
|
|
185
|
+
const childReads = run.localAgent ? collectReadSkillNames(run.localAgent.session) : /* @__PURE__ */ new Set();
|
|
186
|
+
const result = await run.result;
|
|
187
|
+
if (!result.structured) return true;
|
|
188
|
+
const snapshot = policy();
|
|
189
|
+
const plan = result.structured;
|
|
190
|
+
const policyFingerprint = fingerprintPolicy(snapshot);
|
|
191
|
+
const validation = validateEvolutionPlan(plan, {
|
|
192
|
+
sessionSeq: session.seq - 1,
|
|
193
|
+
maxOpsPerPlan: snapshot?.maxOpsPerPlan ?? DEFAULT_MAX_OPS_PER_PLAN,
|
|
194
|
+
protectedSkillNames: new Set(snapshot?.protectedSkillNames ?? []),
|
|
195
|
+
maxMemoryChars: snapshot?.memoryChars ?? DEFAULT_MEMORY_CHAR_LIMIT,
|
|
196
|
+
maxUserChars: snapshot?.userChars ?? DEFAULT_USER_CHAR_LIMIT,
|
|
197
|
+
maxSkillContentChars: snapshot?.skillContentChars ?? DEFAULT_SKILL_CONTENT_CHARS
|
|
198
|
+
});
|
|
199
|
+
const acceptedSkillOps = validation.accepted.skillOps ?? [];
|
|
200
|
+
const skippedUnread = filterUnreadSkillOps(acceptedSkillOps, new Set([...collectReadSkillNames(session), ...childReads]));
|
|
201
|
+
const actions = await executePlan(validation.accepted);
|
|
202
|
+
const evidenceQuotes = [...validation.accepted.memoryOps ?? [], ...acceptedSkillOps].reduce((total, op) => total + (Array.isArray(op.evidence) ? op.evidence.length : 0), 0);
|
|
203
|
+
ctx.emit("evolution/plan-applied", {
|
|
204
|
+
sessionId: session.id,
|
|
205
|
+
planId: randomUUID(),
|
|
206
|
+
policyFingerprint,
|
|
207
|
+
memoryApplied: actions.filter((action) => action.startsWith("Memory")).length,
|
|
208
|
+
skillApplied: actions.filter((action) => action.startsWith("Skill ")).length,
|
|
209
|
+
rejectedOps: validation.rejected.length + skippedUnread,
|
|
210
|
+
evidenceQuotes,
|
|
211
|
+
estimatedInputChars: reviewText.length
|
|
212
|
+
});
|
|
213
|
+
if (actions.length > 0) agent.inject(createUserMessage({
|
|
214
|
+
content: [{
|
|
215
|
+
type: "text",
|
|
216
|
+
text: `💾 Self-improvement review: ${actions.join(" · ")}`
|
|
217
|
+
}],
|
|
218
|
+
source: {
|
|
219
|
+
kind: "plugin",
|
|
220
|
+
plugin: "dsh-evolution-review",
|
|
221
|
+
form: "notice",
|
|
222
|
+
summary: "self-improvement review"
|
|
223
|
+
}
|
|
224
|
+
}));
|
|
225
|
+
return true;
|
|
226
|
+
} finally {
|
|
227
|
+
try {
|
|
228
|
+
await run.dispose();
|
|
229
|
+
} catch (disposeError) {
|
|
230
|
+
ctx.logger.warn(`dsh-evolution-review: subagent dispose failed: ${disposeError instanceof Error ? disposeError.message : String(disposeError)}`);
|
|
218
231
|
}
|
|
219
|
-
}
|
|
220
|
-
return true;
|
|
232
|
+
}
|
|
221
233
|
} catch (error) {
|
|
222
234
|
ctx.logger.warn(`dsh-evolution-review: subagent review failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
223
235
|
return false;
|
|
@@ -352,6 +364,23 @@ function collectReadSkillNames(session) {
|
|
|
352
364
|
}
|
|
353
365
|
return names;
|
|
354
366
|
}
|
|
367
|
+
/** Map/set size that triggers a dead-session counter sweep (bounded, not a hard cap). */
|
|
368
|
+
const COUNTER_SWEEP_THRESHOLD = 128;
|
|
369
|
+
/**
|
|
370
|
+
* Remove every entry whose session is no longer live (rc.42 audit P1-10):
|
|
371
|
+
* `turnStarts` / `cumulativeToolCalls` / `completionInjected` are keyed by
|
|
372
|
+
* SessionId with no platform session-end hook to prune against, so they grew
|
|
373
|
+
* unbounded over a long-lived host. Works for maps and sets; returns the
|
|
374
|
+
* number of removed entries.
|
|
375
|
+
*/
|
|
376
|
+
function sweepDeadSessionEntries(entries, isAlive) {
|
|
377
|
+
let removed = 0;
|
|
378
|
+
for (const id of [...entries.keys()]) if (!isAlive(id)) {
|
|
379
|
+
entries.delete(id);
|
|
380
|
+
removed += 1;
|
|
381
|
+
}
|
|
382
|
+
return removed;
|
|
383
|
+
}
|
|
355
384
|
/**
|
|
356
385
|
* Drop mutating ops whose target was not read this session, in place.
|
|
357
386
|
* Create is exempt (no read required to author a new skill). Covers the same
|
|
@@ -421,4 +450,4 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars)
|
|
|
421
450
|
].join("\n");
|
|
422
451
|
}
|
|
423
452
|
//#endregion
|
|
424
|
-
export { Config, apply, collectReadSkillNames, filterUnreadSkillOps, inject, name, shouldCompletionReview };
|
|
453
|
+
export { COUNTER_SWEEP_THRESHOLD, Config, apply, collectReadSkillNames, filterUnreadSkillOps, inject, name, shouldCompletionReview, sweepDeadSessionEntries };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -38,6 +38,16 @@ export declare function shouldCompletionReview(reason: {
|
|
|
38
38
|
} | undefined, sessionToolCalls: number, minToolCalls: number): boolean;
|
|
39
39
|
/** Skill names this session loaded (read-before-write source for the background review). */
|
|
40
40
|
export declare function collectReadSkillNames(session: Session): Set<string>;
|
|
41
|
+
/** Map/set size that triggers a dead-session counter sweep (bounded, not a hard cap). */
|
|
42
|
+
export declare const COUNTER_SWEEP_THRESHOLD = 128;
|
|
43
|
+
/**
|
|
44
|
+
* Remove every entry whose session is no longer live (rc.42 audit P1-10):
|
|
45
|
+
* `turnStarts` / `cumulativeToolCalls` / `completionInjected` are keyed by
|
|
46
|
+
* SessionId with no platform session-end hook to prune against, so they grew
|
|
47
|
+
* unbounded over a long-lived host. Works for maps and sets; returns the
|
|
48
|
+
* number of removed entries.
|
|
49
|
+
*/
|
|
50
|
+
export declare function sweepDeadSessionEntries<K>(entries: Map<K, unknown> | Set<K>, isAlive: (id: K) => boolean): number;
|
|
41
51
|
/**
|
|
42
52
|
* Drop mutating ops whose target was not read this session, in place.
|
|
43
53
|
* Create is exempt (no read required to author a new skill). Covers the same
|
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.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.43",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
36
|
-
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.
|
|
37
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.1.0-rc.
|
|
36
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.43",
|
|
37
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.1.0-rc.43"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
|
|
44
44
|
"@deepseek-ai/dsh-session": "^0.1.0-rc.6",
|
|
45
45
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
46
|
-
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.
|
|
46
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.43"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.6",
|
|
55
55
|
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.6",
|
|
56
56
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
57
|
-
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.
|
|
58
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.1.0-rc.
|
|
59
|
-
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.
|
|
57
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.43",
|
|
58
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.1.0-rc.43",
|
|
59
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.43"
|
|
60
60
|
}
|
|
61
61
|
}
|