rlhf-feedback-loop 0.6.2 → 0.6.3
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/README.md +2 -0
- package/bin/cli.js +33 -13
- package/package.json +1 -1
- package/scripts/hook-auto-capture.sh +69 -0
- package/src/api/server.js +12 -5
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ One command. Pick your platform:
|
|
|
23
23
|
| **Claude** | `claude mcp add rlhf -- npx -y rlhf-feedback-loop serve` |
|
|
24
24
|
| **Codex** | `codex mcp add rlhf -- npx -y rlhf-feedback-loop serve` |
|
|
25
25
|
| **Gemini** | `gemini mcp add rlhf -- npx -y rlhf-feedback-loop serve` |
|
|
26
|
+
| **Amp** | `cp node_modules/rlhf-feedback-loop/plugins/amp-skill/SKILL.md .amp/skills/rlhf-feedback/SKILL.md` |
|
|
27
|
+
| **Cursor** | `cursor mcp add rlhf -- npx -y rlhf-feedback-loop serve` |
|
|
26
28
|
| **All at once** | `npx add-mcp rlhf-feedback-loop` |
|
|
27
29
|
|
|
28
30
|
That's it. Your agent can now capture feedback, recall past learnings mid-conversation, and block repeated mistakes.
|
package/bin/cli.js
CHANGED
|
@@ -210,19 +210,39 @@ function capture() {
|
|
|
210
210
|
return;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
213
|
+
const signal = (args.feedback || '').toLowerCase();
|
|
214
|
+
const normalized = ['up', 'thumbsup', 'thumbs_up', 'positive'].some(v => signal.includes(v)) ? 'up'
|
|
215
|
+
: ['down', 'thumbsdown', 'thumbs_down', 'negative'].some(v => signal.includes(v)) ? 'down'
|
|
216
|
+
: signal;
|
|
217
|
+
|
|
218
|
+
if (normalized !== 'up' && normalized !== 'down') {
|
|
219
|
+
console.error('Missing or unrecognized --feedback=up|down');
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const result = captureFeedback({
|
|
224
|
+
signal: normalized,
|
|
225
|
+
context: args.context || '',
|
|
226
|
+
whatWentWrong: args['what-went-wrong'],
|
|
227
|
+
whatToChange: args['what-to-change'],
|
|
228
|
+
whatWorked: args['what-worked'],
|
|
229
|
+
tags: args.tags,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
if (result.accepted) {
|
|
233
|
+
const ev = result.feedbackEvent;
|
|
234
|
+
const mem = result.memoryRecord;
|
|
235
|
+
console.log(`\nRLHF Feedback Captured [${normalized.toUpperCase()}]`);
|
|
236
|
+
console.log('─'.repeat(50));
|
|
237
|
+
console.log(` Feedback ID : ${ev.id}`);
|
|
238
|
+
console.log(` Signal : ${ev.signal} (${ev.actionType})`);
|
|
239
|
+
console.log(` Memory ID : ${mem.id}`);
|
|
240
|
+
console.log(` Storage : JSONL log + LanceDB vector index\n`);
|
|
241
|
+
} else {
|
|
242
|
+
console.log(`\nRLHF Feedback Recorded [${normalized.toUpperCase()}] — not promoted`);
|
|
243
|
+
console.log('─'.repeat(50));
|
|
244
|
+
console.log(` Reason : ${result.reason}\n`);
|
|
245
|
+
process.exit(2);
|
|
226
246
|
}
|
|
227
247
|
}
|
|
228
248
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rlhf-feedback-loop",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
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": {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Claude Code UserPromptSubmit hook — auto-captures thumbs up/down feedback
|
|
3
|
+
# Triggered on every user message. Only acts on feedback signals.
|
|
4
|
+
# Shows full verbose output with storage paths, memory IDs, and stats.
|
|
5
|
+
|
|
6
|
+
PROMPT="$CLAUDE_USER_PROMPT"
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
CAPTURE="$SCRIPT_DIR/../.claude/scripts/feedback/capture-feedback.js"
|
|
9
|
+
FEEDBACK_LOG="$SCRIPT_DIR/../.claude/memory/feedback/feedback-log.jsonl"
|
|
10
|
+
MEMORY_LOG="$SCRIPT_DIR/../.claude/memory/feedback/memory-log.jsonl"
|
|
11
|
+
|
|
12
|
+
# Normalize to lowercase for matching
|
|
13
|
+
LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]')
|
|
14
|
+
|
|
15
|
+
capture_and_report() {
|
|
16
|
+
local SIGNAL="$1"
|
|
17
|
+
|
|
18
|
+
# Capture feedback (verbose output already shows IDs, signal, storage)
|
|
19
|
+
node "$CAPTURE" --feedback="$SIGNAL" --context="$PROMPT" --tags="auto-capture,hook"
|
|
20
|
+
|
|
21
|
+
# Show storage proof
|
|
22
|
+
echo ""
|
|
23
|
+
echo "Storage Proof:"
|
|
24
|
+
echo " Feedback log : $FEEDBACK_LOG ($(wc -l < "$FEEDBACK_LOG" 2>/dev/null || echo 0) entries)"
|
|
25
|
+
echo " Memory log : $MEMORY_LOG ($(wc -l < "$MEMORY_LOG" 2>/dev/null || echo 0) entries)"
|
|
26
|
+
echo " LanceDB : $SCRIPT_DIR/../.claude/memory/feedback/lancedb/"
|
|
27
|
+
echo ""
|
|
28
|
+
|
|
29
|
+
# Show last entry written
|
|
30
|
+
echo "Last Entry Written:"
|
|
31
|
+
tail -1 "$FEEDBACK_LOG" 2>/dev/null | node -e "
|
|
32
|
+
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
|
33
|
+
console.log(' ID :', d.id);
|
|
34
|
+
console.log(' Signal :', d.signal, '(' + d.actionType + ')');
|
|
35
|
+
console.log(' Context :', (d.context||'').slice(0,80));
|
|
36
|
+
console.log(' Tags :', (d.tags||[]).join(', '));
|
|
37
|
+
console.log(' Timestamp :', d.timestamp);
|
|
38
|
+
console.log(' Domain :', (d.richContext||{}).domain || 'general');
|
|
39
|
+
" 2>/dev/null
|
|
40
|
+
|
|
41
|
+
# Show cumulative stats
|
|
42
|
+
echo ""
|
|
43
|
+
echo "Cumulative Stats:"
|
|
44
|
+
node -e "
|
|
45
|
+
const fs = require('fs');
|
|
46
|
+
const lines = fs.readFileSync('$FEEDBACK_LOG','utf8').trim().split('\n').filter(Boolean);
|
|
47
|
+
const entries = lines.map(l => { try { return JSON.parse(l); } catch(e) { return null; } }).filter(Boolean);
|
|
48
|
+
const pos = entries.filter(e => e.signal === 'positive').length;
|
|
49
|
+
const neg = entries.filter(e => e.signal === 'negative').length;
|
|
50
|
+
const promoted = entries.filter(e => e.actionType === 'store-learning' || e.actionType === 'store-mistake').length;
|
|
51
|
+
console.log(' Total feedback :', entries.length);
|
|
52
|
+
console.log(' Positive (up) :', pos);
|
|
53
|
+
console.log(' Negative (down) :', neg);
|
|
54
|
+
console.log(' Promoted to mem :', promoted);
|
|
55
|
+
console.log(' Ratio :', pos > 0 ? (pos/(pos+neg)*100).toFixed(0) + '% positive' : 'n/a');
|
|
56
|
+
" 2>/dev/null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Check for thumbs up signals
|
|
60
|
+
if echo "$LOWER" | grep -qE '(thumbs? ?up|that worked|looks good|nice work|perfect|good job)'; then
|
|
61
|
+
capture_and_report "up"
|
|
62
|
+
exit 0
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Check for thumbs down signals
|
|
66
|
+
if echo "$LOWER" | grep -qE '(thumbs? ?down|that failed|that was wrong|fix this)'; then
|
|
67
|
+
capture_and_report "down"
|
|
68
|
+
exit 0
|
|
69
|
+
fi
|
package/src/api/server.js
CHANGED
|
@@ -183,7 +183,18 @@ function createApiServer() {
|
|
|
183
183
|
const parsed = new URL(req.url, 'http://localhost');
|
|
184
184
|
const pathname = parsed.pathname;
|
|
185
185
|
|
|
186
|
-
//
|
|
186
|
+
// Public endpoints — no auth required
|
|
187
|
+
if (req.method === 'GET' && pathname === '/') {
|
|
188
|
+
sendJson(res, 200, {
|
|
189
|
+
name: 'rlhf-feedback-loop',
|
|
190
|
+
version: pkg.version,
|
|
191
|
+
status: 'ok',
|
|
192
|
+
docs: 'https://github.com/IgorGanapolsky/rlhf-feedback-loop',
|
|
193
|
+
endpoints: ['/health', '/v1/feedback/capture', '/v1/feedback/stats', '/v1/dpo/export'],
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
187
198
|
if (req.method === 'GET' && pathname === '/health') {
|
|
188
199
|
sendJson(res, 200, {
|
|
189
200
|
status: 'ok',
|
|
@@ -409,10 +420,6 @@ function createApiServer() {
|
|
|
409
420
|
return;
|
|
410
421
|
}
|
|
411
422
|
|
|
412
|
-
if (req.method === 'GET' && pathname === '/') {
|
|
413
|
-
sendText(res, 200, 'RLHF Feedback Loop API is running.');
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
423
|
|
|
417
424
|
// ----------------------------------------------------------------
|
|
418
425
|
// Billing routes
|