rlhf-feedback-loop 0.6.3 → 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.
@@ -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/bin/cli.js CHANGED
@@ -258,9 +258,10 @@ function summary() {
258
258
  }
259
259
 
260
260
  function exportDpo() {
261
+ const extraArgs = process.argv.slice(3).join(' ');
261
262
  try {
262
263
  const output = execSync(
263
- `node "${path.join(PKG_ROOT, 'scripts', 'export-dpo-pairs.js')}"`,
264
+ `node "${path.join(PKG_ROOT, 'scripts', 'export-dpo-pairs.js')}" --from-local ${extraArgs}`,
264
265
  { encoding: 'utf8', stdio: 'pipe', cwd: CWD }
265
266
  );
266
267
  process.stdout.write(output);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rlhf-feedback-loop",
3
- "version": "0.6.3",
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": {