@noobdemon/noob-cli 1.9.5 → 1.9.6
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 +29 -0
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -416,6 +416,25 @@ function buildUserMessage(history) {
|
|
|
416
416
|
return parts.join("\n");
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
+
// Detect câu trả lời bị cắt giữa chừng — KHÔNG phải câu hoàn chỉnh.
|
|
420
|
+
// Trả true nếu text kết thúc đột ngột (thiếu dấu câu, list chưa đóng, v.v.).
|
|
421
|
+
function isIncompleteResponse(text) {
|
|
422
|
+
if (!text) return false;
|
|
423
|
+
const t = text.trimEnd();
|
|
424
|
+
// Kết thúc bằng dấu cuối danh sách chưa đóng: "A.", "B.", "1.", "(1)" mà không có gì sau
|
|
425
|
+
if (/[A-Z]\.\s*$/.test(t) || /\(\d+\)\s*$/.test(t) || /^\d+\.\s*$/m.test(t)) return true;
|
|
426
|
+
// Kết thúc giữa câu — không có dấu câu cuối cùng (. ! ? : ; ) và không phải markdown/code
|
|
427
|
+
const lastChar = t.slice(-1);
|
|
428
|
+
if (lastChar && !/[.!?:;)\]"'`#>\n]/.test(lastChar) && t.length > 50) {
|
|
429
|
+
// Kiểm thêm: dòng cuối chứa từ khóa bị cắt (ví dụ, vd, hay, hoặc, và, nhưng, mà)
|
|
430
|
+
const lastLine = t.split("\n").pop().trim();
|
|
431
|
+
if (/\s(ví|vd|hay|hoặc|và|nhưng|mà|hoac|or|and|but|e\.g|i\.e)\s*$/i.test(lastLine)) return true;
|
|
432
|
+
// Dòng cuối là 1 câu bắt đầu nhưng chưa xong (có chủ ngữ nhưng không có vị ngữ hoàn chỉnh)
|
|
433
|
+
if (/\s(Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn|Bạn)\s+(muốn|có|thấy|nên|cần|đã|đang|sẽ|chọn|chọn|chọn)\s*$/i.test(lastLine)) return true;
|
|
434
|
+
}
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
|
|
419
438
|
// Extract a single tool call from an assistant message, if present.
|
|
420
439
|
// NOTE: we do NOT match up to a closing ``` fence — write_file content routinely
|
|
421
440
|
// contains its own ```code``` fences (e.g. a README), and the first inner fence
|
|
@@ -523,6 +542,16 @@ export async function runAgent({ history, model, signal, onTool, onStatus, onDel
|
|
|
523
542
|
});
|
|
524
543
|
continue;
|
|
525
544
|
}
|
|
545
|
+
// Phát hiện câu trả lời bị cắt giữa chừng (truncated stream): text kết thúc
|
|
546
|
+
// đột ngột không có dấu câu/đóng danh sách/tool block → nudge model viết tiếp.
|
|
547
|
+
if (isIncompleteResponse(text)) {
|
|
548
|
+
history.push({
|
|
549
|
+
role: "tool",
|
|
550
|
+
name: "stream_recovery",
|
|
551
|
+
content: "[STREAM CUT] Lượt vừa bị cắt giữa chừng. Hãy viết TIẾP liền mạch — nếu đang hỏi user thì hoàn tất câu hỏi, nếu đang list thì đóng danh sách, nếu đang viết tool block thì đóng đúng JSON.",
|
|
552
|
+
});
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
526
555
|
return text; // final answer
|
|
527
556
|
}
|
|
528
557
|
|