@noobdemon/noob-cli 1.9.1 → 1.9.2
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/package.json +1 -1
- package/src/agent.js +28 -0
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -43,6 +43,7 @@ Context is finite. Don't slurp the whole repo up front. Discover information pro
|
|
|
43
43
|
• A server/service the USER wants to keep using (they asked to "run the app/server") → leave it running, and tell the user it is up: its id and the URL/port, and that they can ask you to stop it when done (you will kill_bg it). It also stops automatically when noob exits.
|
|
44
44
|
• If bg_output shows it exited with a non-zero code or an error, treat it like a failed command: read the output and fix, don't silently move on.
|
|
45
45
|
- Keep prose tight. Explain what you did and why, not how to use a tool.
|
|
46
|
+
- Do NOT call the same tool with the same input repeatedly. The runtime detects loops and will force a step change. If you need to re-read a file, use the data already in your history.
|
|
46
47
|
- JSON in the tool block must be valid: escape newlines as \\n inside string values.
|
|
47
48
|
- LANGUAGE: Always write your prose answers to the user in Vietnamese (tiếng Việt), unless the user explicitly writes in another language. Keep code, file paths, commands, and tool JSON unchanged.
|
|
48
49
|
|
|
@@ -77,6 +78,11 @@ Follow this pattern exactly. Your very first response to a task that needs the f
|
|
|
77
78
|
// Số bước tool tối đa cho một lượt. Đặt rất cao theo yêu cầu người dùng: task
|
|
78
79
|
// dài cứ chạy, đừng tự dừng. Người dùng vẫn có thể Ctrl+C bất cứ lúc nào.
|
|
79
80
|
const MAX_STEPS = 10000;
|
|
81
|
+
|
|
82
|
+
// Loop detection: nếu model gọi cùng 1 tool với input giống nhau liên tiếp
|
|
83
|
+
// quá ngưỡng này → coi là bị kẹt, inject thông báo để model chuyển bước.
|
|
84
|
+
const LOOP_DETECT_WINDOW = 3;
|
|
85
|
+
const LOOP_DETECT_THRESHOLD = 2;
|
|
80
86
|
const MAX_PROMPT_CHARS = 80000; // ngân sách ký tự cho phần hội thoại gửi lên model
|
|
81
87
|
// Khi history vượt ngưỡng này, gọi model phụ tóm tắt các lượt cũ thay vì cắt cụt
|
|
82
88
|
// → giữ được "trí nhớ dài hạn" trong phiên mà không nổ context.
|
|
@@ -408,6 +414,7 @@ export async function runAgent({ history, model, signal, onTool, onStatus, onDel
|
|
|
408
414
|
// [GỠ BUDGET 2026-06-06] Không còn token budget enforcement. Agent/loop/sub-agent
|
|
409
415
|
// chạy không giới hạn token. Dừng theo: GOAL đạt, <<LOOP_DONE>>, <<ULTRA_DONE>>,
|
|
410
416
|
// model tự kết thúc reply không có tool block, hoặc user Ctrl+C.
|
|
417
|
+
const recentCalls = []; // {name, inputStr} — theo dõi vòng lặp
|
|
411
418
|
for (let step = 0; step < MAX_STEPS; step++) {
|
|
412
419
|
// Mỗi 100 bước log một mốc để người dùng biết noob vẫn đang chạy (task dài).
|
|
413
420
|
if (step > 0 && step % 100 === 0) onStatus?.(`đã chạy ${step} bước…`);
|
|
@@ -460,6 +467,27 @@ export async function runAgent({ history, model, signal, onTool, onStatus, onDel
|
|
|
460
467
|
name: call.name,
|
|
461
468
|
content: allow ? result : t.toolDenied,
|
|
462
469
|
});
|
|
470
|
+
|
|
471
|
+
// ── Loop detection ──────────────────────────────────────────────────
|
|
472
|
+
// Theo dõi N tool call gần nhất. Nếu cùng tên + input giống nhau liên tiếp
|
|
473
|
+
// quá ngưỡng → model bị kẹt. Inject thông báo nhắc model chuyển bước,
|
|
474
|
+
// KHÔNG ngắt task (vẫn có thể Ctrl+C thủ công).
|
|
475
|
+
const inputStr = JSON.stringify(call.input || {});
|
|
476
|
+
recentCalls.push({ name: call.name, inputStr });
|
|
477
|
+
if (recentCalls.length > LOOP_DETECT_WINDOW) recentCalls.shift();
|
|
478
|
+
if (recentCalls.length >= LOOP_DETECT_THRESHOLD + 1) {
|
|
479
|
+
const lastN = recentCalls.slice(-LOOP_DETECT_THRESHOLD);
|
|
480
|
+
const allSame = lastN.every((c) => c.name === lastN[0].name && c.inputStr === lastN[0].inputStr);
|
|
481
|
+
if (allSame) {
|
|
482
|
+
// Đã lặp — inject cảnh báo, xoá calls để tránh trigger liên tục
|
|
483
|
+
recentCalls.length = 0;
|
|
484
|
+
history.push({
|
|
485
|
+
role: "tool",
|
|
486
|
+
name: "loop_detection",
|
|
487
|
+
content: `[LOOP DETECTED] Bạn vừa gọi ${lastN[0].name} ${LOOP_DETECT_THRESHOLD} lần liên tiếp với cùng input — có vẻ bạn đang bị kẹt trong vòng lặp. HÃY CHUYỂN BƯỚC: gọi tool khác, hoặc trả lời Markdown nếu đã xong. KHÔNG được gọi cùng tool cùng input lần nữa.`,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
463
491
|
}
|
|
464
492
|
return t.maxSteps;
|
|
465
493
|
}
|