rlhf-feedback-loop 0.6.4 → 0.6.5
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/adapters/mcp/server-stdio.js +64 -0
- package/package.json +1 -1
|
@@ -249,9 +249,73 @@ function parseOptionalObject(input, name) {
|
|
|
249
249
|
throw new Error(`${name} must be an object`);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
function detectFeedbackSignal(text) {
|
|
253
|
+
const lower = String(text || '').toLowerCase();
|
|
254
|
+
const UP = /\b(thumbs?\s*up|that worked|looks good|nice work|perfect|good job)\b/;
|
|
255
|
+
const DOWN = /\b(thumbs?\s*down|that failed|that was wrong|fix this)\b/;
|
|
256
|
+
if (UP.test(lower)) return 'up';
|
|
257
|
+
if (DOWN.test(lower)) return 'down';
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function formatStats() {
|
|
262
|
+
const logPath = path.join(SAFE_DATA_DIR, 'feedback-log.jsonl');
|
|
263
|
+
const memPath = path.join(SAFE_DATA_DIR, 'memory-log.jsonl');
|
|
264
|
+
if (!fs.existsSync(logPath)) return 'No feedback captured yet.';
|
|
265
|
+
const lines = fs.readFileSync(logPath, 'utf8').trim().split('\n').filter(Boolean);
|
|
266
|
+
const entries = lines.map(l => { try { return JSON.parse(l); } catch (_) { return null; } }).filter(Boolean);
|
|
267
|
+
const pos = entries.filter(e => e.signal === 'positive').length;
|
|
268
|
+
const neg = entries.filter(e => e.signal === 'negative').length;
|
|
269
|
+
const memCount = fs.existsSync(memPath) ? fs.readFileSync(memPath, 'utf8').trim().split('\n').filter(Boolean).length : 0;
|
|
270
|
+
return [
|
|
271
|
+
'## Storage Proof',
|
|
272
|
+
` Feedback log : ${logPath} (${entries.length} entries)`,
|
|
273
|
+
` Memory log : ${memPath} (${memCount} entries)`,
|
|
274
|
+
` LanceDB : ${path.join(SAFE_DATA_DIR, 'lancedb/')}`,
|
|
275
|
+
'',
|
|
276
|
+
'## Cumulative Stats',
|
|
277
|
+
` Total feedback : ${entries.length}`,
|
|
278
|
+
` Positive (up) : ${pos}`,
|
|
279
|
+
` Negative (down) : ${neg}`,
|
|
280
|
+
` Promoted to mem : ${memCount}`,
|
|
281
|
+
` Ratio : ${pos > 0 ? (pos / (pos + neg) * 100).toFixed(0) + '% positive' : 'n/a'}`,
|
|
282
|
+
].join('\n');
|
|
283
|
+
}
|
|
284
|
+
|
|
252
285
|
async function callTool(name, args = {}) {
|
|
253
286
|
assertToolAllowed(name, getActiveMcpProfile());
|
|
254
287
|
|
|
288
|
+
// Platform-agnostic auto-capture: detect feedback signals in any tool call
|
|
289
|
+
const textToCheck = args.query || args.context || '';
|
|
290
|
+
const autoSignal = detectFeedbackSignal(textToCheck);
|
|
291
|
+
if (autoSignal && name !== 'capture_feedback') {
|
|
292
|
+
const autoResult = captureFeedback({
|
|
293
|
+
signal: autoSignal,
|
|
294
|
+
context: textToCheck,
|
|
295
|
+
tags: ['auto-capture', 'mcp'],
|
|
296
|
+
});
|
|
297
|
+
const ev = autoResult.feedbackEvent || {};
|
|
298
|
+
const autoReport = [
|
|
299
|
+
'',
|
|
300
|
+
`## Auto-Captured Feedback [${autoSignal.toUpperCase()}]`,
|
|
301
|
+
` Feedback ID : ${ev.id || 'n/a'}`,
|
|
302
|
+
` Signal : ${ev.signal || autoSignal} (${ev.actionType || 'unknown'})`,
|
|
303
|
+
` Context : ${(ev.context || textToCheck).slice(0, 80)}`,
|
|
304
|
+
` Timestamp : ${ev.timestamp || new Date().toISOString()}`,
|
|
305
|
+
` Promoted : ${autoResult.accepted ? 'yes (Memory ID: ' + (autoResult.memoryRecord || {}).id + ')' : 'no — ' + (autoResult.reason || '')}`,
|
|
306
|
+
'',
|
|
307
|
+
formatStats(),
|
|
308
|
+
].join('\n');
|
|
309
|
+
// Prepend the auto-capture report to whatever the tool was going to return
|
|
310
|
+
const toolResult = await callToolInner(name, args);
|
|
311
|
+
toolResult.content[0].text = autoReport + '\n\n---\n\n' + toolResult.content[0].text;
|
|
312
|
+
return toolResult;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return callToolInner(name, args);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async function callToolInner(name, args = {}) {
|
|
255
319
|
if (name === 'recall') {
|
|
256
320
|
const query = args.query || '';
|
|
257
321
|
const limit = Number(args.limit || 5);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rlhf-feedback-loop",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Make your AI agent learn from mistakes. Capture thumbs up/down feedback, block repeated failures, export DPO training data. Works with ChatGPT, Claude, Codex, Gemini, Amp.",
|
|
5
5
|
"homepage": "https://github.com/IgorGanapolsky/rlhf-feedback-loop#readme",
|
|
6
6
|
"repository": {
|