blun-king-cli 9.1.444 → 9.1.445
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/bin/validated-learning-outcome-trace.cjs +107 -0
- package/blun.mjs +20 -3
- package/package.json +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const SCHEMA_VERSION = 1;
|
|
8
|
+
const MAX_LESSONS = 5;
|
|
9
|
+
const MAX_HEADING_CHARS = 160;
|
|
10
|
+
const MAX_SEMANTIC_MATCHES = 6;
|
|
11
|
+
const CANDIDATE_ID = /^vl-[a-f0-9]{32}$/u;
|
|
12
|
+
|
|
13
|
+
function cleanText(value, maxChars) {
|
|
14
|
+
const text = String(value ?? '')
|
|
15
|
+
.replace(/[\u0000-\u001f\u007f]+/gu, ' ')
|
|
16
|
+
.replace(/\s+/gu, ' ')
|
|
17
|
+
.trim();
|
|
18
|
+
return text.slice(0, maxChars);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function lessonKey(reference, heading) {
|
|
22
|
+
return crypto.createHash('sha256')
|
|
23
|
+
.update(`${String(reference ?? '')}\0${heading}`)
|
|
24
|
+
.digest('hex')
|
|
25
|
+
.slice(0, 24);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function normalizeLessons(value) {
|
|
29
|
+
if (!Array.isArray(value)) return [];
|
|
30
|
+
const lessons = [];
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
for (const item of value) {
|
|
33
|
+
const heading = cleanText(item?.heading, MAX_HEADING_CHARS);
|
|
34
|
+
if (!heading) continue;
|
|
35
|
+
const key = lessonKey(item?.reference, heading);
|
|
36
|
+
if (seen.has(key)) continue;
|
|
37
|
+
seen.add(key);
|
|
38
|
+
const semanticMatches = [...new Set(
|
|
39
|
+
(Array.isArray(item?.semanticMatches) ? item.semanticMatches : [])
|
|
40
|
+
.map((tag) => cleanText(tag, 48))
|
|
41
|
+
.filter(Boolean),
|
|
42
|
+
)].sort().slice(0, MAX_SEMANTIC_MATCHES);
|
|
43
|
+
lessons.push({
|
|
44
|
+
lessonKey: key,
|
|
45
|
+
heading,
|
|
46
|
+
...(semanticMatches.length > 0 ? { semanticMatches } : {}),
|
|
47
|
+
});
|
|
48
|
+
if (lessons.length >= MAX_LESSONS) break;
|
|
49
|
+
}
|
|
50
|
+
return lessons;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function atomicCreate(filePath, value) {
|
|
54
|
+
const temporary = `${filePath}.${process.pid}.${crypto.randomBytes(8).toString('hex')}.tmp`;
|
|
55
|
+
fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
56
|
+
try {
|
|
57
|
+
fs.linkSync(temporary, filePath);
|
|
58
|
+
return true;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (error?.code !== 'EEXIST') throw error;
|
|
61
|
+
return false;
|
|
62
|
+
} finally {
|
|
63
|
+
fs.rmSync(temporary, { force: true });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function readTrace(filePath) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function recordValidatedLearningOutcomeTrace(candidate, selectedLessons, options = {}) {
|
|
76
|
+
if (candidate?.source !== 'current_turn'
|
|
77
|
+
|| candidate.status !== 'pending'
|
|
78
|
+
|| !CANDIDATE_ID.test(String(candidate.id ?? ''))
|
|
79
|
+
|| typeof candidate.filePath !== 'string'
|
|
80
|
+
|| !candidate.filePath) return null;
|
|
81
|
+
const lessons = normalizeLessons(selectedLessons);
|
|
82
|
+
if (lessons.length === 0) return null;
|
|
83
|
+
|
|
84
|
+
const directory = path.dirname(candidate.filePath);
|
|
85
|
+
const filePath = path.join(directory, `${candidate.id}.lesson-exposure.jsonl`);
|
|
86
|
+
const trace = {
|
|
87
|
+
schemaVersion: SCHEMA_VERSION,
|
|
88
|
+
type: 'lesson_exposure_red_green',
|
|
89
|
+
status: 'observed',
|
|
90
|
+
candidateId: candidate.id,
|
|
91
|
+
outcome: 'validated_red_green',
|
|
92
|
+
causalAttribution: false,
|
|
93
|
+
lessons,
|
|
94
|
+
recordedAt: new Date((options.now || Date.now)()).toISOString(),
|
|
95
|
+
};
|
|
96
|
+
const created = atomicCreate(filePath, trace);
|
|
97
|
+
return {
|
|
98
|
+
created,
|
|
99
|
+
filePath,
|
|
100
|
+
trace: created ? trace : readTrace(filePath),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
normalizeLessons,
|
|
106
|
+
recordValidatedLearningOutcomeTrace,
|
|
107
|
+
};
|
package/blun.mjs
CHANGED
|
@@ -231592,6 +231592,7 @@ var init_mistake_md = __esmMin((() => {
|
|
|
231592
231592
|
reserveChecked = false;
|
|
231593
231593
|
mistakeDir;
|
|
231594
231594
|
mistakeFile;
|
|
231595
|
+
selectedLessons = [];
|
|
231595
231596
|
constructor(agent) {
|
|
231596
231597
|
super(agent);
|
|
231597
231598
|
this.mistakeDir = resolveMistakeDir(agent.blunHomeDir);
|
|
@@ -231600,6 +231601,10 @@ var init_mistake_md = __esmMin((() => {
|
|
|
231600
231601
|
onContextClear() {
|
|
231601
231602
|
super.onContextClear();
|
|
231602
231603
|
this.reserveChecked = false;
|
|
231604
|
+
this.selectedLessons = [];
|
|
231605
|
+
}
|
|
231606
|
+
getSelectedLessons() {
|
|
231607
|
+
return this.selectedLessons.map((lesson) => ({ ...lesson }));
|
|
231603
231608
|
}
|
|
231604
231609
|
async inject() {
|
|
231605
231610
|
const injection = await this.getInjection();
|
|
@@ -231619,6 +231624,7 @@ var init_mistake_md = __esmMin((() => {
|
|
|
231619
231624
|
});
|
|
231620
231625
|
}
|
|
231621
231626
|
async getInjection() {
|
|
231627
|
+
this.selectedLessons = [];
|
|
231622
231628
|
try {
|
|
231623
231629
|
if (isLowInformationMistakeTurn(this.agent.context.history)) return void 0;
|
|
231624
231630
|
const sources = await readProjectMistakeSources(this.agent);
|
|
@@ -231638,6 +231644,7 @@ var init_mistake_md = __esmMin((() => {
|
|
|
231638
231644
|
const query = mistakeQueryTextForTurn(this.agent.context.history, this.agent.goal.getGoal().goal);
|
|
231639
231645
|
const selected = selectRelevantMistakeSources(sources, query);
|
|
231640
231646
|
if (!selected.text) return void 0;
|
|
231647
|
+
this.selectedLessons = selected.selected;
|
|
231641
231648
|
let prefix = "";
|
|
231642
231649
|
if (!this.reserveChecked && sharedContent) {
|
|
231643
231650
|
this.reserveChecked = true;
|
|
@@ -232243,13 +232250,19 @@ function buildValidatedLearningSignalReminder(signal) {
|
|
|
232243
232250
|
lines.push("</validated-learning-signal>");
|
|
232244
232251
|
return lines.join("\n");
|
|
232245
232252
|
}
|
|
232246
|
-
var ValidatedLearningSignalInjector, shouldSyncValidatedLearningCandidate, syncValidatedLearningCandidate;
|
|
232253
|
+
var ValidatedLearningSignalInjector, recordValidatedLearningOutcomeTrace, shouldSyncValidatedLearningCandidate, syncValidatedLearningCandidate;
|
|
232247
232254
|
var init_validated_learning_signal = __esmMin((() => {
|
|
232248
232255
|
init_injector();
|
|
232249
232256
|
({ syncValidatedLearningCandidate } = createRequire(import.meta.url)("./bin/validated-learning-signal.cjs"));
|
|
232250
232257
|
({ shouldSyncValidatedLearningCandidate } = createRequire(import.meta.url)("./bin/validated-learning-performance-policy.cjs"));
|
|
232258
|
+
({ recordValidatedLearningOutcomeTrace } = createRequire(import.meta.url)("./bin/validated-learning-outcome-trace.cjs"));
|
|
232251
232259
|
ValidatedLearningSignalInjector = class extends DynamicInjector {
|
|
232252
232260
|
injectionVariant = "validated_learning_signal";
|
|
232261
|
+
selectedLessons;
|
|
232262
|
+
constructor(agent, selectedLessons) {
|
|
232263
|
+
super(agent);
|
|
232264
|
+
this.selectedLessons = selectedLessons;
|
|
232265
|
+
}
|
|
232253
232266
|
async inject() {
|
|
232254
232267
|
const existing = this.agent.context.history.filter(isValidatedLearningSignalReminder);
|
|
232255
232268
|
if (!shouldSyncValidatedLearningCandidate(this.agent.context.history)) return;
|
|
@@ -232262,6 +232275,9 @@ var init_validated_learning_signal = __esmMin((() => {
|
|
|
232262
232275
|
if (existing.length > 0) this.agent.context.removeSystemRemindersMatching(isValidatedLearningSignalReminder);
|
|
232263
232276
|
return;
|
|
232264
232277
|
}
|
|
232278
|
+
if (signal.source === "current_turn") try {
|
|
232279
|
+
recordValidatedLearningOutcomeTrace(signal, this.selectedLessons?.() ?? []);
|
|
232280
|
+
} catch {}
|
|
232265
232281
|
const injection = buildValidatedLearningSignalReminder(signal);
|
|
232266
232282
|
const expected = `<system-reminder>\n${injection}\n</system-reminder>`;
|
|
232267
232283
|
if (existing.length === 1 && reminderText(existing[0]) === expected) return;
|
|
@@ -233086,13 +233102,14 @@ var init_manager$2 = __esmMin((() => {
|
|
|
233086
233102
|
missionContractInjector = null;
|
|
233087
233103
|
constructor(agent) {
|
|
233088
233104
|
this.agent = agent;
|
|
233105
|
+
const mistakeMdInjector = new MistakeMdInjector(agent);
|
|
233089
233106
|
this.injectors = [
|
|
233090
233107
|
new PluginSessionStartInjector(agent),
|
|
233091
233108
|
new ErrorMemoryInjector(agent),
|
|
233092
233109
|
new ToolAwarenessInjector(agent),
|
|
233093
|
-
|
|
233110
|
+
mistakeMdInjector,
|
|
233094
233111
|
new RepeatedAssistantResponseInjector(agent),
|
|
233095
|
-
new ValidatedLearningSignalInjector(agent),
|
|
233112
|
+
new ValidatedLearningSignalInjector(agent, () => mistakeMdInjector.getSelectedLessons()),
|
|
233096
233113
|
new ActionStyleInjector(agent),
|
|
233097
233114
|
new PlanModeInjector(agent),
|
|
233098
233115
|
new PermissionModeInjector(agent)
|