@lmzhen/dsh-evolution-feedback 0.1.0-rc.65 → 0.1.0-rc.67
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 +41 -36
- package/lib/types/index.d.ts +3 -1
- package/package.json +6 -6
package/lib/index.js
CHANGED
|
@@ -65,7 +65,7 @@ function evolutionIoAdapter(provider) {
|
|
|
65
65
|
* changes semantically: the bundle digest is the fail-closed signal for
|
|
66
66
|
* review workers, so a stale id across deployments must be distinguishable.
|
|
67
67
|
*/
|
|
68
|
-
const PROMPT_BUNDLE_ID = "dsh-evolution@
|
|
68
|
+
const PROMPT_BUNDLE_ID = "dsh-evolution@7";
|
|
69
69
|
const MEMORY_REVIEW_PROMPT = `[Auto-review — Memory]
|
|
70
70
|
Review the conversation above and consider saving to memory if appropriate.
|
|
71
71
|
|
|
@@ -86,6 +86,8 @@ Signals to look for (any one of these warrants action):
|
|
|
86
86
|
• Non-trivial technique, fix, workaround, debugging path, or tool-usage pattern emerged that a future session would benefit from. Capture it.
|
|
87
87
|
• A skill that got loaded or consulted this session turned out to be wrong, missing a step, or outdated. Patch it NOW.
|
|
88
88
|
|
|
89
|
+
Read-before-write (enforced by this channel): update, patch, delete, or write support files ONLY into skills you loaded or read in THIS session — ops on unread skills are dropped; CREATE of a brand-new umbrella is the only exception.
|
|
90
|
+
|
|
89
91
|
Preference order — prefer the earliest action that fits, but do pick one when a signal above fired:
|
|
90
92
|
1. UPDATE A CURRENTLY-LOADED SKILL. Look back through the conversation for skills the user loaded or you read. If any of them covers the territory of the new learning, PATCH that one first. It is the skill that was in play, so it's the right one to extend.
|
|
91
93
|
2. UPDATE AN EXISTING UMBRELLA. If no loaded skill fits but an existing class-level skill does, patch it. Add a subsection, a pitfall, or broaden a trigger.
|
|
@@ -133,6 +135,8 @@ Signals that warrant a skill update (any one is enough):
|
|
|
133
135
|
• Non-trivial technique, fix, workaround, or debugging path emerged.
|
|
134
136
|
• A skill that was loaded or consulted turned out wrong, missing, or outdated — patch it now.
|
|
135
137
|
|
|
138
|
+
Read-before-write (enforced by this channel): update, patch, delete, or write support files ONLY into skills you loaded or read in THIS session — ops on unread skills are dropped; CREATE of a brand-new umbrella is the only exception.
|
|
139
|
+
|
|
136
140
|
Preference order for skills — pick the earliest that fits:
|
|
137
141
|
1. UPDATE A CURRENTLY-LOADED SKILL. Check what skills were loaded or read in the conversation. If one of them covers the learning, PATCH it first. It was in play; it's the right place.
|
|
138
142
|
2. UPDATE AN EXISTING UMBRELLA. Patch it.
|
|
@@ -240,12 +244,12 @@ function sha256(text) {
|
|
|
240
244
|
function createPromptBundle(prompts) {
|
|
241
245
|
const canonical = JSON.stringify({
|
|
242
246
|
id: PROMPT_BUNDLE_ID,
|
|
243
|
-
version:
|
|
247
|
+
version: 7,
|
|
244
248
|
prompts: Object.fromEntries(Object.entries(prompts).sort())
|
|
245
249
|
});
|
|
246
250
|
return Object.freeze({
|
|
247
251
|
id: PROMPT_BUNDLE_ID,
|
|
248
|
-
version:
|
|
252
|
+
version: 7,
|
|
249
253
|
prompts: Object.freeze({ ...prompts }),
|
|
250
254
|
sha256: sha256(canonical)
|
|
251
255
|
});
|
|
@@ -281,8 +285,10 @@ var EvolutionFeedback = class {
|
|
|
281
285
|
};
|
|
282
286
|
chain = Promise.resolve();
|
|
283
287
|
path;
|
|
288
|
+
io;
|
|
284
289
|
constructor(io, home = process.env.DSH_HOME ?? join(homedir(), ".dsh"), pathOverride) {
|
|
285
290
|
if (io) this.path = pathOverride ?? join(home, "evolution", "feedback.json");
|
|
291
|
+
this.io = io;
|
|
286
292
|
}
|
|
287
293
|
mutate(task) {
|
|
288
294
|
const run = this.chain.then(task, task);
|
|
@@ -311,7 +317,8 @@ var EvolutionFeedback = class {
|
|
|
311
317
|
});
|
|
312
318
|
}
|
|
313
319
|
record(target, rating, note, kind = "session", io) {
|
|
314
|
-
const
|
|
320
|
+
const mode = kind === "skill" ? "skills" : "sessions";
|
|
321
|
+
const table = this.state[mode];
|
|
315
322
|
const current = table[target] ?? {
|
|
316
323
|
positive: 0,
|
|
317
324
|
negative: 0
|
|
@@ -319,7 +326,31 @@ var EvolutionFeedback = class {
|
|
|
319
326
|
current[rating] += 1;
|
|
320
327
|
if (note !== void 0) current.lastNote = note;
|
|
321
328
|
table[target] = current;
|
|
322
|
-
|
|
329
|
+
const recordIo = io ?? this.io;
|
|
330
|
+
const path = this.path;
|
|
331
|
+
if (!recordIo || !path) return;
|
|
332
|
+
this.mutate(async () => {
|
|
333
|
+
try {
|
|
334
|
+
await transactIo(recordIo, path, (raw) => {
|
|
335
|
+
if (raw !== null) try {
|
|
336
|
+
JSON.parse(raw);
|
|
337
|
+
} catch {
|
|
338
|
+
return Promise.resolve(raw);
|
|
339
|
+
}
|
|
340
|
+
const diskState = parseState(raw);
|
|
341
|
+
const diskTable = diskState[mode];
|
|
342
|
+
const diskRec = diskTable[target] ?? {
|
|
343
|
+
positive: 0,
|
|
344
|
+
negative: 0
|
|
345
|
+
};
|
|
346
|
+
diskRec[rating] += 1;
|
|
347
|
+
if (note !== void 0) diskRec.lastNote = note;
|
|
348
|
+
diskTable[target] = diskRec;
|
|
349
|
+
this.state = diskState;
|
|
350
|
+
return Promise.resolve(JSON.stringify(diskState, null, 2));
|
|
351
|
+
});
|
|
352
|
+
} catch (error) {}
|
|
353
|
+
});
|
|
323
354
|
}
|
|
324
355
|
score(target, kind = "session") {
|
|
325
356
|
const record = (kind === "skill" ? this.state.skills : this.state.sessions)[target];
|
|
@@ -334,16 +365,9 @@ var EvolutionFeedback = class {
|
|
|
334
365
|
sessions: { ...this.state.sessions }
|
|
335
366
|
};
|
|
336
367
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
await this.mutate(async () => {
|
|
341
|
-
await transactIo(io, path, (current) => {
|
|
342
|
-
const merged = mergeStates(parseState(current), this.state);
|
|
343
|
-
this.state = merged;
|
|
344
|
-
return Promise.resolve(JSON.stringify(merged, null, 2));
|
|
345
|
-
});
|
|
346
|
-
});
|
|
368
|
+
/** Await the pending record-task chain (unload safety; rc.66). */
|
|
369
|
+
waitIdle() {
|
|
370
|
+
return this.chain;
|
|
347
371
|
}
|
|
348
372
|
};
|
|
349
373
|
/** Parse a raw feedback sidecar; malformed reads as empty (best-effort). */
|
|
@@ -365,25 +389,6 @@ function parseState(raw) {
|
|
|
365
389
|
};
|
|
366
390
|
}
|
|
367
391
|
}
|
|
368
|
-
/** Deep-merge two feedback states: union by target; in-memory values win on
|
|
369
|
-
* conflict. NOTE (v3 audit P3 reviewed): additive counting was rejected — a
|
|
370
|
-
* restart merge (restore+flush) would double-count the same records, and a
|
|
371
|
-
* stateless JSON sidecar cannot distinguish "two processes incrementing the
|
|
372
|
-
* same target" from "the same record seen twice". Cross-process same-target
|
|
373
|
-
* increments stay a documented limitation; an append-only event log would be
|
|
374
|
-
* the real fix. */
|
|
375
|
-
function mergeStates(disk, memory) {
|
|
376
|
-
return {
|
|
377
|
-
skills: {
|
|
378
|
-
...disk.skills,
|
|
379
|
-
...memory.skills
|
|
380
|
-
},
|
|
381
|
-
sessions: {
|
|
382
|
-
...disk.sessions,
|
|
383
|
-
...memory.sessions
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
392
|
const name = "evolution-feedback";
|
|
388
393
|
const Config = z.object({
|
|
389
394
|
qualityWarnThreshold: z.number().default(-.25),
|
|
@@ -412,8 +417,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
412
417
|
};
|
|
413
418
|
}
|
|
414
419
|
ctx.effect(() => () => {
|
|
415
|
-
|
|
416
|
-
}, "evolution-feedback.
|
|
420
|
+
return feedback.waitIdle();
|
|
421
|
+
}, "evolution-feedback.records");
|
|
417
422
|
}
|
|
418
423
|
//#endregion
|
|
419
424
|
export { Config, EvolutionFeedback, apply, name };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -28,13 +28,15 @@ export declare class EvolutionFeedback {
|
|
|
28
28
|
private state;
|
|
29
29
|
private chain;
|
|
30
30
|
private readonly path?;
|
|
31
|
+
private readonly io;
|
|
31
32
|
constructor(io?: IoLike, home?: string, pathOverride?: string);
|
|
32
33
|
private mutate;
|
|
33
34
|
restore(io: IoLike): Promise<void>;
|
|
34
35
|
record(target: string, rating: 'positive' | 'negative', note?: string, kind?: 'skill' | 'session', io?: IoLike): void;
|
|
35
36
|
score(target: string, kind?: 'skill' | 'session'): number;
|
|
36
37
|
snapshot(): FeedbackState;
|
|
37
|
-
|
|
38
|
+
/** Await the pending record-task chain (unload safety; rc.66). */
|
|
39
|
+
waitIdle(): Promise<unknown>;
|
|
38
40
|
}
|
|
39
41
|
export declare const name = "evolution-feedback";
|
|
40
42
|
export interface Config {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-feedback",
|
|
3
3
|
"description": "Feedback-to-quality scoring for self-evolution (community build)",
|
|
4
|
-
"version": "0.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.67",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
39
39
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
40
|
-
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.
|
|
41
|
-
"@lmzhen/dsh-skill-usage": "^0.1.0-rc.
|
|
40
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.67",
|
|
41
|
+
"@lmzhen/dsh-skill-usage": "^0.1.0-rc.67"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
45
|
-
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.
|
|
46
|
-
"@lmzhen/dsh-evolution-io-node": "^0.1.0-rc.
|
|
47
|
-
"@lmzhen/dsh-skill-usage": "^0.1.0-rc.
|
|
45
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.67",
|
|
46
|
+
"@lmzhen/dsh-evolution-io-node": "^0.1.0-rc.67",
|
|
47
|
+
"@lmzhen/dsh-skill-usage": "^0.1.0-rc.67"
|
|
48
48
|
}
|
|
49
49
|
}
|