@noobdemon/noob-cli 1.12.6 → 1.12.8

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/CHANGELOG.md CHANGED
@@ -2,7 +2,21 @@
2
2
 
3
3
  Tất cả thay đổi đáng kể của `@noobdemon/noob-cli` được ghi vào file này.
4
4
 
5
- ## [1.12.6] - 2026-06-12
5
+ ## [1.12.8] - 2026-06-13
6
+
7
+ ### Added
8
+ - **Claude Opus 4.8** (`gateway-claude-opus-4-8`, provider `anthropic`, tier `flagship`) — set làm `DEFAULT_MODEL` mới.
9
+
10
+ ### Removed
11
+ - **Rút catalog xuống 3 flagship** (`src/models.js`): chỉ còn `gateway-claude-opus-4-8`, `gateway-gpt-5-5`, `gateway-deepseek-v4-pro`. Gỡ toàn bộ 32 model cũ: o3/o3-mini/o4-mini/DeepSeek R1/Qwen QwQ (reasoning), GPT-5 Mini/Nano + Gemini Flash + DeepSeek V4 Flash + GPT-4.1 Mini/Nano (fast), Gemini 2.5/3/3.1 Pro, Grok 3/4, Qwen 3 Max, Kimi K2, Llama 3.3 70B, Claude Sonnet 4/4.6, Opus 4.1/4.5/4.6/4.7, GPT-5/5.1/5.3/5.4/4o/5 Online. `PROVIDERS` map còn 3 entry (`openai`/`anthropic`/`deepseek`).
12
+
13
+ ### Changed
14
+ - **Worker `claude-code-proxy`** (`worker/src/worker.js`): `mapModel` map "opus/claude/sonnet/haiku" → `opus-4-8`, "gpt/o3/o4" → `gpt-5-5`, "deepseek" → `deepseek-v4-pro`; fallback default → `opus-4-8`. `modelsList()` chỉ còn 3 id mới. Đã deploy (version `689b94d1`).
15
+
16
+ ## [1.12.7] - 2026-06-12
17
+
18
+ ### Changed
19
+ - **Gỡ auto-compact, chuyển sang MANUAL only** (`src/repl.js` + `src/tokens.js` + `src/agent.js`): trước đây CLI tự gọi `maybeSummarize({force:true})` khi context đạt 75% — gián đoạn workflow giữa chừng và summary có thể mất chi tiết user cần. Giờ user toàn quyền quyết định khi nào tóm tắt bằng `/compact`. Chỉ còn 2 mốc CẢNH BÁO (không auto-action): **60% (120k tokens)** nhắc nhẹ một lần, **80% (160k tokens)** cảnh báo mạnh gợi ý gõ `/compact` trước khi provider reject ở ~200k. Đồng thời sửa bug `CONTEXT_WINDOW=2_000_000` → `200_000` (khớp Claude Opus 4.7 + GPT-4o); ngưỡng cũ 2M khiến 75% = 1.5M token không bao giờ chạm → user báo `/compact không hoạt động`. `SUMMARIZE_THRESHOLD_CHARS` 6M → 600k, `MAX_PROMPT_CHARS` 1.2M → 800k, `keepTail` 16/24 → 12/16 cho khớp window thực.
6
20
 
7
21
  ### Added
8
22
  - **Tool `write_todos`** (`src/repl/agent-dispatch.js` + `src/tools.js` + `src/agent.js`): tool ẢO để model declare structured todo list thay vì viết markdown `- [ ]`. Shape `{todos: [{text, done}]}` — REPLACE toàn bộ list mỗi lần gọi (no patch). Dispatcher intercept TRƯỚC `execTool`: set `state.todos` + `tui.setTodos` trực tiếp, set flag `state._todosFromTool=true` để `repl.js` skip parse markdown sau turn (tránh overwrite structured state). In compact box lần đầu, diff (chỉ dòng đổi) các lần sau. SYSTEM prompt rule TODO-BASED EXECUTION đã update: model PHẢI dùng `write_todos`, không viết markdown. Lý do: parser markdown cũ (`parseTodosFromHistory`) fragile khi model format sai (sai indent, dùng `*` thay `-`, thiếu space). Structured tool call → CLI render luôn đúng, progress bar trên status line cập nhật ngay. Stub trong `TOOLS.write_todos` làm fail-safe nếu lỡ qua `runTool` trực tiếp. Smoke `scripts/smoke-write-todos.mjs` 27/27 pass + regression `smoke-dispatch.mjs` 23/23 pass.
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@noobdemon/noob-cli",
3
- "version": "1.12.6",
3
+ "version": "1.12.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "description": "Trợ lý lập trình agentic trong terminal (kiểu Claude Code), tiếng Việt, dùng sức mạnh Noob Demon — 34 mô hình AI.",
7
+ "description": "Trợ lý lập trình agentic trong terminal (kiểu Claude Code), tiếng Việt, dùng sức mạnh Noob Demon — 3 mô hình flagship (Claude Opus 4.8, GPT-5.5, DeepSeek V4 Pro).",
8
8
  "type": "module",
9
9
  "bin": {
10
10
  "noob": "bin/noob.js"
package/src/agent.js CHANGED
@@ -146,10 +146,12 @@ const MAX_STEPS = 10000;
146
146
  // loop detection cũ bằng cách xen kẽ 2-3 tool call khác nhau.
147
147
  const LOOP_DETECT_WINDOW = 6;
148
148
  const LOOP_DETECT_THRESHOLD = 2;
149
- const MAX_PROMPT_CHARS = 1200000; // ~300k tokens (ngang context window) — compact() KHÔNG chạy trước auto-compact 80% (240k token) của repl.js
149
+ const MAX_PROMPT_CHARS = 800000; // ~200k tokens (ngang CONTEXT_WINDOW) — compact() safety net cuối, repl.js auto-compact ở 75% (150k token) chạy trước.
150
150
  // 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
151
151
  // → giữ được "trí nhớ dài hạn" trong phiên mà không nổ context.
152
- const SUMMARIZE_THRESHOLD_CHARS = 6000000; // ~1.5M tokens (75% window) summarize chỉ chạy sau auto-compact 75% với CONTEXT_WINDOW=2M
152
+ // 600k chars 150k tokens = trùng ngưỡng auto-compact 75% của repl.js. Khi
153
+ // /compact thủ công hoặc auto-compact gọi với force=true thì ngưỡng này bị bypass.
154
+ const SUMMARIZE_THRESHOLD_CHARS = 600000;
153
155
 
154
156
  // HARD GOAL block (do /goal <text> set): chèn ngay sau memoryBlock, attention
155
157
  // cao. Mục đích — chống 3 failure mode bài "dynamic workflows" của Anthropic
@@ -262,11 +264,11 @@ export async function maybeSummarize(history, { model, signal, force = false } =
262
264
  const totalChars = history.reduce((s, m) => s + (m.content?.length || 0), 0);
263
265
  if (!force && totalChars < SUMMARIZE_THRESHOLD_CHARS) return false;
264
266
  // Giữ tail nguyên vẹn; tóm tắt phần trước.
265
- // Với CONTEXT_WINDOW = 2M tokens, tail cần đủ lớn để giữ context tool result
266
- // gần nhất (vd 10 lượt cuối có thể là chuỗi edit_file + run_command đang dở).
267
- // force (gọi từ /compact hoặc auto-compact 75%): giữ 16 tail.
268
- // non-force: giữ 24 tail (rộng tay hơn vì phiên rất dài mới trigger).
269
- const keepTail = force ? 16 : 24;
267
+ // Với CONTEXT_WINDOW = 200k tokens, tail cần đủ để giữ vài lượt tool result
268
+ // gần nhất (chuỗi edit_file + run_command đang dở).
269
+ // force (gọi từ /compact hoặc auto-compact 75%): giữ 12 tail.
270
+ // non-force: giữ 16 tail (rộng tay hơn vì phiên dài mới trigger).
271
+ const keepTail = force ? 12 : 16;
270
272
  if (history.length <= keepTail + 2) return false;
271
273
  // Nếu lượt đầu đã là summary (role=system, name=summary) → tóm tắt thêm.
272
274
  const head = history.slice(0, history.length - keepTail);
package/src/models.js CHANGED
@@ -1,98 +1,27 @@
1
1
  // Model catalog supported by the Noob Demon gateway.
2
2
  export const MODELS = [
3
- { id: 'gateway-gpt-5', name: 'GPT-5', provider: 'openai', tier: 'flagship' },
4
- { id: 'gateway-gpt-5-1', name: 'GPT-5.1', provider: 'openai', tier: 'flagship' },
5
- { id: 'gateway-gpt-5-3', name: 'GPT-5.3', provider: 'openai', tier: 'flagship' },
6
- { id: 'gateway-gpt-5-4', name: 'GPT-5.4', provider: 'openai', tier: 'flagship' },
7
- { id: 'gateway-gpt-5-5', name: 'GPT-5.5', provider: 'openai', tier: 'flagship' },
8
- { id: 'gateway-gpt-o3', name: 'o3', provider: 'openai', tier: 'reasoning' },
9
- { id: 'gateway-gpt-o3-mini', name: 'o3 Mini', provider: 'openai', tier: 'reasoning' },
10
- { id: 'gateway-gpt-o4-mini', name: 'o4-mini', provider: 'openai', tier: 'reasoning' },
11
- { id: 'gateway-gpt-4o', name: 'GPT-4o', provider: 'openai', tier: 'standard' },
12
- { id: 'gateway-gpt-4-1-mini', name: 'GPT-4.1 Mini', provider: 'openai', tier: 'fast' },
13
- { id: 'gateway-gpt-4-1-nano', name: 'GPT-4.1 Nano', provider: 'openai', tier: 'fast' },
14
- { id: 'gateway-gpt-5-mini', name: 'GPT-5 Mini', provider: 'openai', tier: 'fast' },
15
- { id: 'gateway-gpt-5-nano', name: 'GPT-5 Nano', provider: 'openai', tier: 'fast' },
16
- { id: 'gateway-gpt-5-online', name: 'GPT-5 Online', provider: 'openai', tier: 'standard' },
17
- {
18
- id: 'gateway-claude-opus-4-7',
19
- name: 'Claude Opus 4.7',
20
- provider: 'anthropic',
21
- tier: 'flagship',
22
- },
23
- {
24
- id: 'gateway-claude-opus-4-6',
25
- name: 'Claude Opus 4.6',
26
- provider: 'anthropic',
27
- tier: 'flagship',
28
- },
29
3
  {
30
- id: 'gateway-claude-opus-4-5',
31
- name: 'Claude Opus 4.5',
4
+ id: 'gateway-claude-opus-4-8',
5
+ name: 'Claude Opus 4.8',
32
6
  provider: 'anthropic',
33
7
  tier: 'flagship',
34
8
  },
35
- {
36
- id: 'gateway-claude-opus-4-1',
37
- name: 'Claude Opus 4.1',
38
- provider: 'anthropic',
39
- tier: 'standard',
40
- },
41
- {
42
- id: 'gateway-claude-sonnet-4',
43
- name: 'Claude Sonnet 4',
44
- provider: 'anthropic',
45
- tier: 'standard',
46
- },
47
- {
48
- id: 'gateway-claude-sonnet-4-6',
49
- name: 'Claude Sonnet 4.6',
50
- provider: 'anthropic',
51
- tier: 'standard',
52
- },
53
- { id: 'gateway-google-2.5-pro', name: 'Gemini 2.5 Pro', provider: 'google', tier: 'flagship' },
54
- { id: 'gateway-gemini-3-pro', name: 'Gemini 3 Pro', provider: 'google', tier: 'flagship' },
55
- { id: 'gateway-gemini-3-1-pro', name: 'Gemini 3.1 Pro', provider: 'google', tier: 'flagship' },
56
- { id: 'gateway-gemini-2.5-flash', name: 'Gemini 2.5 Flash', provider: 'google', tier: 'fast' },
9
+ { id: 'gateway-gpt-5-5', name: 'GPT-5.5', provider: 'openai', tier: 'flagship' },
57
10
  {
58
11
  id: 'gateway-deepseek-v4-pro',
59
12
  name: 'DeepSeek V4 Pro',
60
13
  provider: 'deepseek',
61
14
  tier: 'flagship',
62
15
  },
63
- {
64
- id: 'gateway-deepseek-v4-flash',
65
- name: 'DeepSeek V4 Flash',
66
- provider: 'deepseek',
67
- tier: 'fast',
68
- },
69
- { id: 'gateway-deepseek-r1', name: 'DeepSeek R1', provider: 'deepseek', tier: 'reasoning' },
70
- { id: 'gateway-deepseek-v3', name: 'DeepSeek V3', provider: 'deepseek', tier: 'standard' },
71
- { id: 'gateway-grok-4', name: 'Grok 4', provider: 'xai', tier: 'flagship' },
72
- { id: 'gateway-grok-3', name: 'Grok 3', provider: 'xai', tier: 'standard' },
73
- { id: 'gateway-qwen-3-max', name: 'Qwen 3 Max', provider: 'alibaba', tier: 'standard' },
74
- { id: 'gateway-qwen-qwq-32b', name: 'Qwen QwQ 32B', provider: 'alibaba', tier: 'reasoning' },
75
- { id: 'gateway-deepinfra-kimi-k2', name: 'Kimi K2', provider: 'moonshot', tier: 'standard' },
76
- {
77
- id: 'gateway-llama-3-3-70b-versatile',
78
- name: 'Llama 3.3 70B',
79
- provider: 'meta',
80
- tier: 'standard',
81
- },
82
16
  ];
83
17
 
84
18
  export const PROVIDERS = {
85
19
  openai: { name: 'OpenAI', color: '#10a37f' },
86
20
  anthropic: { name: 'Anthropic', color: '#d97706' },
87
- google: { name: 'Google', color: '#3b82f6' },
88
21
  deepseek: { name: 'DeepSeek', color: '#06b6d4' },
89
- xai: { name: 'xAI', color: '#ef4444' },
90
- alibaba: { name: 'Alibaba', color: '#8b5cf6' },
91
- moonshot: { name: 'Moonshot', color: '#ec4899' },
92
- meta: { name: 'Meta', color: '#6366f1' },
93
22
  };
94
23
 
95
- export const DEFAULT_MODEL = 'gateway-claude-opus-4-7';
24
+ export const DEFAULT_MODEL = 'gateway-claude-opus-4-8';
96
25
 
97
26
  export function findModel(id) {
98
27
  if (!id || typeof id !== 'string') return undefined;
package/src/repl.js CHANGED
@@ -1481,53 +1481,24 @@ NGUYÊN TẮC:
1481
1481
  // Reset turn-scoped auto-approve — chỉ áp dụng trong runAgent vừa rồi.
1482
1482
  // (autoApprove + autoApproveFile vẫn giữ nguyên cho phiên.)
1483
1483
  state.autoApproveTurn.clear();
1484
- // Auto-compact dựa trên context tokens thay chars.
1485
- // Với CONTEXT_WINDOW = 2M tokens (xem src/tokens.js):
1486
- // 75% (1.5M tokens) auto compact
1487
- // 60% (1.2M tokens) cảnh báo mạnh
1488
- // 40% (800k tokens) nhắc nhẹ
1489
- // Ngưỡng kéo xuống model context dài hiện tại để 80% mới compact thì
1490
- // mỗi lượt cuối đã ăn 200k+ tokens — auto-compact sớm hơn giữ phiên mượt.
1484
+ // [2026-06-12] GỠ AUTO-COMPACT user kiểm soát compact thủ công bằng /compact.
1485
+ // do: auto-compact gián đoạn workflow giữa chừng, summary có thể mất chi
1486
+ // tiết user cần. Giữ 2 mốc CẢNH BÁO (60% / 80%) để user biết khi nào nên
1487
+ // chạy /compact, nhưng KHÔNG tự động chạy nữa.
1488
+ // Với CONTEXT_WINDOW = 200k tokens:
1489
+ // 60% (120k) nhắc nhẹ một lần
1490
+ // 80% (160k) cảnh báo mạnh nên /compact ngay trước khi provider reject
1491
1491
  try {
1492
1492
  const totalTokens = countMessages(state.history);
1493
1493
  const k = Math.round(totalTokens / 1000);
1494
1494
  const pct = Math.round((totalTokens / CONTEXT_WINDOW) * 100);
1495
- // Mốc 3 (≥75% 1.5M tokens): TỰ ĐỘNG compact.
1496
- if (totalTokens >= CONTEXT_WINDOW * 0.75 && !state._autoCompacting) {
1497
- state._autoCompacting = true;
1498
- console.log(c.accent(` ⚡ ${t.autoCompactTrigger(k)} (${pct}% context)`));
1499
- tui.setBusy(true, t.compactRunning);
1500
- try {
1501
- const ok = await maybeSummarize(state.history, { model: state.model, force: true });
1502
- tui.setBusy(false);
1503
- if (ok) {
1504
- const afterTokens = countMessages(state.history);
1505
- const aK = Math.round(afterTokens / 1000);
1506
- const saved =
1507
- totalTokens > 0 ? Math.round(((totalTokens - afterTokens) / totalTokens) * 100) : 0;
1508
- console.log(
1509
- c.ok(
1510
- ` ${t.autoCompactDone(k, aK, saved)} (${Math.round((afterTokens / CONTEXT_WINDOW) * 100)}% context)`
1511
- )
1512
- );
1513
- state._longSessionWarned = false;
1514
- persist();
1515
- } else {
1516
- console.log(c.err(' ' + t.autoCompactFail));
1517
- }
1518
- } catch (e) {
1519
- tui.setBusy(false);
1520
- console.log(c.err(' ' + t.autoCompactFail));
1521
- } finally {
1522
- state._autoCompacting = false;
1523
- }
1524
- } else if (totalTokens >= CONTEXT_WINDOW * 0.6) {
1525
- // Mốc 2 (≥60% — 1.2M tokens): cảnh báo mạnh.
1526
- console.log(c.err(` ⚠ ${t.veryLongSession(k)} (${pct}% context)`));
1495
+ if (totalTokens >= CONTEXT_WINDOW * 0.8) {
1496
+ // Mốc 2 (≥80% 160k tokens): cảnh báo mạnh, gợi ý /compact ngay.
1497
+ console.log(c.err(` ⚠ ${t.veryLongSession(k)} (${pct}% context) — gõ /compact để tóm tắt, tránh provider reject ở ~200k.`));
1527
1498
  state._longSessionWarned = true;
1528
- } else if (totalTokens >= CONTEXT_WINDOW * 0.4 && !state._longSessionWarned) {
1529
- // Mốc 1 (≥40% — 800k tokens): nhắc nhẹ một lần.
1530
- console.log(c.dim(` ⓘ ${t.longSession(k)} (${pct}% context)`));
1499
+ } else if (totalTokens >= CONTEXT_WINDOW * 0.6 && !state._longSessionWarned) {
1500
+ // Mốc 1 (≥60% — 120k tokens): nhắc nhẹ một lần.
1501
+ console.log(c.dim(` ⓘ ${t.longSession(k)} (${pct}% context) — cân nhắc /compact nếu phiên còn dài.`));
1531
1502
  state._longSessionWarned = true;
1532
1503
  }
1533
1504
  } catch {}
package/src/tokens.js CHANGED
@@ -57,8 +57,12 @@ export function countMessages(messages = []) {
57
57
  // window đủ rộng (256 chars) để qua mọi ranh giới token thực tế của cl100k/o200k
58
58
  // (token dài nhất ~ vài chục byte).
59
59
  const TAIL_WINDOW = 256;
60
- // Context window tối đa của model (2M tokens). Dùng để tính % usage realtime.
61
- export const CONTEXT_WINDOW = 2_000_000;
60
+ // Context window tối đa của model. Đặt 200k tokens match Claude 3.5/Opus 4,
61
+ // GPT-4o, an toàn cho mọi model phổ biến qua gateway (Gemini 1M, DeepSeek
62
+ // 128k, Grok 128k...). Đặt cao hơn 200k là vô nghĩa: provider sẽ reject prompt
63
+ // TRƯỚC khi auto-compact của repl.js có cơ hội trigger → user thấy 'compact
64
+ // không hoạt động' dù logic compact vẫn đúng.
65
+ export const CONTEXT_WINDOW = 200_000;
62
66
 
63
67
  export class TokenMeter {
64
68
  constructor() {