@noobdemon/noob-cli 1.10.2 → 1.10.4
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 +25 -27
- package/src/repl.js +3 -3
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -242,24 +242,6 @@ export function compact(history, budget) {
|
|
|
242
242
|
return [...head, elided, ...out.slice(tailStart)];
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
// Trích xuất todo items chưa hoàn thành từ history assistant messages.
|
|
246
|
-
// Format: `- [ ] task` (unchecked) / `- [x] task` (checked).
|
|
247
|
-
// Trả về mảng text của các item chưa check, giữ nguyên thứ tự.
|
|
248
|
-
function extractUncheckedTodos(history) {
|
|
249
|
-
const todos = [];
|
|
250
|
-
for (const m of history) {
|
|
251
|
-
if (m.role !== "assistant" || typeof m.content !== "string") continue;
|
|
252
|
-
for (const line of m.content.split("\n")) {
|
|
253
|
-
const unchecked = line.match(/^[\s]*-\s*\[\s?\]\s+(.+)/);
|
|
254
|
-
if (unchecked) todos.push(unchecked[1].trim());
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// Dedupe: giữ item cuối cùng (model có thể repeat todo).
|
|
258
|
-
const seen = new Map();
|
|
259
|
-
for (const t of todos) seen.set(t, t);
|
|
260
|
-
return [...seen.values()];
|
|
261
|
-
}
|
|
262
|
-
|
|
263
245
|
// Bộ nhớ dài hạn cho phiên: khi history phình to, gọi model phụ TÓM TẮT các
|
|
264
246
|
// lượt cũ thành một message system gọn (giữ quyết định, file đã sửa, lý do,
|
|
265
247
|
// việc dở) rồi thay phần đầu history bằng tóm tắt đó. Mutates `history` in place.
|
|
@@ -509,11 +491,12 @@ function extractJsonObject(s, from) {
|
|
|
509
491
|
* @param {(msg:string)=>void} opts.onStatus thinking/streaming status
|
|
510
492
|
* @returns {Promise<string>} the final assistant answer (no tool block)
|
|
511
493
|
*/
|
|
512
|
-
export async function runAgent({ history, model, signal, onTool, onStatus, onDelta, onSteer, tokenMeter, extraToolsDoc, goal, recentSessions }) {
|
|
494
|
+
export async function runAgent({ history, model, signal, onTool, onStatus, onDelta, onSteer, tokenMeter, extraToolsDoc, goal, recentSessions, pendingTasks }) {
|
|
513
495
|
// [GỠ BUDGET 2026-06-06] Không còn token budget enforcement. Agent/loop/sub-agent
|
|
514
496
|
// chạy không giới hạn token. Dừng theo: GOAL đạt, <<LOOP_DONE>>, <<ULTRA_DONE>>,
|
|
515
497
|
// model tự kết thúc reply không có tool block, hoặc user Ctrl+C.
|
|
516
498
|
const recentCalls = []; // {name, inputStr} — theo dõi vòng lặp
|
|
499
|
+
let idleRecoveries = 0; // đếm số lần idle recovery —max 5 để tránh infinite loop
|
|
517
500
|
// Effort classifier: phân loại task từ user message gốc → set effort level.
|
|
518
501
|
// Chỉ classify 1 lần ở bước đầu, giữ nguyên suốt task (thay đổi giữa chừng gây bất ổn).
|
|
519
502
|
const effort = classifyEffort(history.find((m) => m.role === "user")?.content || "");
|
|
@@ -573,6 +556,22 @@ export async function runAgent({ history, model, signal, onTool, onStatus, onDel
|
|
|
573
556
|
});
|
|
574
557
|
continue;
|
|
575
558
|
}
|
|
559
|
+
// ── Idle recovery: model dừng nhưng còn task chưa xong ────────────
|
|
560
|
+
// Nếu pendingTasks còn items → KHÔNG return, inject nudge rồi continue loop.
|
|
561
|
+
// Giới hạn 5 lần recovery để tránh infinite loop.
|
|
562
|
+
{
|
|
563
|
+
const tasks = pendingTasks || [];
|
|
564
|
+
const remaining = tasks.length;
|
|
565
|
+
if (remaining > 0 && idleRecoveries < 5) {
|
|
566
|
+
idleRecoveries++;
|
|
567
|
+
const next = tasks[0];
|
|
568
|
+
history.push({
|
|
569
|
+
role: "user",
|
|
570
|
+
content: `[SYSTEM] Bạn vừa dừng giữa chừng. Còn ${remaining} việc chưa hoàn thành: ${tasks.map((t) => `"${t}"`).join(", ")}. Việc tiếp theo BẮT BUỘC phải làm ngay: "${next}". Gọi tool (write_file/edit_file/run_command) để làm việc này. KHÔNG dừng, KHÔNG tóm tắt, KHÔNG đợi user.`,
|
|
571
|
+
});
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
576
575
|
return text; // final answer
|
|
577
576
|
}
|
|
578
577
|
|
|
@@ -584,16 +583,15 @@ export async function runAgent({ history, model, signal, onTool, onStatus, onDel
|
|
|
584
583
|
});
|
|
585
584
|
|
|
586
585
|
// ── Todo continuation nudge ──────────────────────────────────────────
|
|
587
|
-
// Sau mỗi tool result,
|
|
588
|
-
//
|
|
586
|
+
// Sau mỗi tool result, inject nudge nếu còn task chưa xong.
|
|
587
|
+
// Dùng pendingTasks (caller gửi vào) thay vì parse output của model.
|
|
589
588
|
{
|
|
590
|
-
const
|
|
591
|
-
if (
|
|
592
|
-
const next =
|
|
589
|
+
const tasks = pendingTasks || [];
|
|
590
|
+
if (tasks.length > 0) {
|
|
591
|
+
const next = tasks[0];
|
|
593
592
|
history.push({
|
|
594
|
-
role: "
|
|
595
|
-
name: "
|
|
596
|
-
content: `[TODO] Còn ${unchecked.length} việc chưa xong. Việc tiếp theo: "${next}". HÃY LÀM NGAY — gọi tool (write_file/edit_file/run_command) để hoàn thành việc này. KHÔNG dừng, KHÔNG tóm tắt, KHÔNG hỏi lại.`,
|
|
593
|
+
role: "user",
|
|
594
|
+
content: `[SYSTEM] Việc "${call.name}" đã hoàn thành. Còn ${tasks.length} việc: ${tasks.map((t) => `"${t}"`).join(", ")}. Việc tiếp theo BẮT BUỘC phải làm ngay: "${next}". Gọi tool (write_file/edit_file/run_command) để làm việc này. KHÔNG dừng, KHÔNG tóm tắt.`,
|
|
597
595
|
});
|
|
598
596
|
}
|
|
599
597
|
}
|
package/src/repl.js
CHANGED
|
@@ -1315,11 +1315,11 @@ NGUYÊN TẮC:
|
|
|
1315
1315
|
signal: abort.signal,
|
|
1316
1316
|
tokenMeter,
|
|
1317
1317
|
goal: state.goal,
|
|
1318
|
-
// Breadcrumbs: 5 phiên gần nhất CÙNG workspace, trừ phiên hiện tại.
|
|
1319
|
-
// Model thấy "đã làm gì" trước đó dù chưa /resume — sửa cảm giác
|
|
1320
|
-
// "model không nhớ session" khi user mở phiên mới trong cùng dự án.
|
|
1321
1318
|
recentSessions: sessions.list(5, process.cwd()).filter((s) => s.id !== session?.id),
|
|
1322
1319
|
extraToolsDoc: state.agentMode ? spawnAgentToolsDoc(0) : "",
|
|
1320
|
+
// Pending tasks: todo items chưa hoàn thành từ lượt trước → model tiếp tục ngay.
|
|
1321
|
+
pendingTasks: (state.todos || []).filter((t) => !t.done).map((t) => t.text),
|
|
1322
|
+
extraToolsDoc: state.agentMode ? spawnAgentToolsDoc(0) : "",
|
|
1323
1323
|
onStatus: () => tick(t.thinking),
|
|
1324
1324
|
onSteer: () => {
|
|
1325
1325
|
if (!pending.length) return [];
|