clew-code 0.2.4 → 0.2.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.
Files changed (57) hide show
  1. package/README.md +264 -292
  2. package/dist/clew-dev.js +5118 -2840
  3. package/dist/main.js +2315 -2090
  4. package/docs/_config.yml +1 -1
  5. package/docs/architecture.html +145 -166
  6. package/docs/architecture.th.html +2 -23
  7. package/docs/commands.html +1 -22
  8. package/docs/commands.th.html +1 -22
  9. package/docs/configuration.html +145 -166
  10. package/docs/configuration.th.html +2 -23
  11. package/docs/css/styles.css +22 -0
  12. package/docs/daemon.html +128 -160
  13. package/docs/daemon.th.html +2 -30
  14. package/docs/features/bridge-mode.html +98 -98
  15. package/docs/features/bridge-mode.th.html +1 -1
  16. package/docs/features/evals.html +181 -181
  17. package/docs/features/evals.th.html +1 -1
  18. package/docs/features/searxng-search.html +150 -150
  19. package/docs/features/searxng-search.th.html +1 -1
  20. package/docs/features/sentry-setup.html +156 -156
  21. package/docs/features/sentry-setup.th.html +1 -1
  22. package/docs/index.html +298 -333
  23. package/docs/index.th.html +1 -36
  24. package/docs/installation.html +103 -124
  25. package/docs/installation.th.html +2 -23
  26. package/docs/internals/growthbook-ab-testing.html +112 -112
  27. package/docs/internals/growthbook-ab-testing.th.html +1 -1
  28. package/docs/internals/hidden-features.html +147 -147
  29. package/docs/internals/hidden-features.th.html +1 -1
  30. package/docs/js/main.js +78 -7
  31. package/docs/loop.html +180 -0
  32. package/docs/loop.th.html +226 -0
  33. package/docs/mcp.html +246 -157
  34. package/docs/mcp.th.html +156 -60
  35. package/docs/models.html +1 -22
  36. package/docs/models.th.html +1 -22
  37. package/docs/peer.html +235 -0
  38. package/docs/peer.th.html +279 -0
  39. package/docs/permission-model.html +101 -122
  40. package/docs/permission-model.th.html +2 -23
  41. package/docs/plugins.html +101 -122
  42. package/docs/plugins.th.html +2 -23
  43. package/docs/providers.html +117 -138
  44. package/docs/providers.th.html +2 -23
  45. package/docs/quick-start.html +92 -120
  46. package/docs/quick-start.th.html +1 -29
  47. package/docs/research-memory.html +79 -111
  48. package/docs/research-memory.th.html +2 -30
  49. package/docs/skills.html +116 -137
  50. package/docs/skills.th.html +2 -23
  51. package/docs/taste.html +96 -29
  52. package/docs/taste.th.html +193 -54
  53. package/docs/tools.html +169 -190
  54. package/docs/tools.th.html +2 -23
  55. package/docs/troubleshooting.html +105 -126
  56. package/docs/troubleshooting.th.html +2 -23
  57. package/package.json +5 -3
@@ -0,0 +1,226 @@
1
+ <!DOCTYPE html>
2
+ <html lang="th">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Agent Loop — Clew Code</title>
7
+ <meta name="description" content="Autonomous agent loop — task queue consumer, worker lifecycle, retry logic, dead-letter queue, lease-based concurrency">
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Noto+Sans+Thai:wght@400;500;600;700&display=swap" rel="stylesheet">
11
+ <link rel="stylesheet" href="css/styles.css">
12
+ <link rel="icon" type="image/svg+xml" href="./assets/clew.svg">
13
+ </head>
14
+ <body>
15
+ <header class="header"></header>
16
+ <div class="app">
17
+ <aside class="sidebar" id="sidebar"></aside>
18
+ <div class="sidebar-overlay" id="sidebarOverlay"></div>
19
+ <div class="content-wrap">
20
+ <main class="content">
21
+ <div class="breadcrumbs"><a href="index.th.html">หน้าแรก</a><span class="sep">/</span><span>Agent Loop</span></div>
22
+ <h1>Autonomous Agent Loop</h1>
23
+ <p class="section-subtitle">Loop ที่รันอัตโนมัติ 24/7 — ดึงงานจากคิว, spawn worker, เช็คสถานะ, retry เมื่อ fail, dead-letter เมื่อเกิน max retry</p>
24
+
25
+ <p>Agent Loop อยู่ใน <code>src/services/autonomous/agentLoop.ts</code> — เป็น consumer ตัวเดียวที่อ่าน task queue และบริหาร lifecycle ของ worker process ทั้งหมด</p>
26
+
27
+ <h2>เทคนิคและหลักการ</h2>
28
+
29
+ <h3>ทำไมต้องเป็น Loop แทนที่จะเป็น Message Queue?</h3>
30
+ <p>ระบบ message queue แบบ RabbitMQ/Kafka มี overhead ในการ setup และ maintenance Agent Loop ใช้<strong>ไฟล์ JSON เป็น persistent queue</strong> — ทำงานได้โดยไม่ต้องมี external dependency:</p>
31
+ <ul>
32
+ <li><strong>Zero external deps</strong> — ใช้ <code>fs.watch</code> ตรวจจับการเปลี่ยนแปลงของไฟล์ queue</li>
33
+ <li><strong>File-based atomicity</strong> — อ่าน/เขียนไฟล์เดียวภายใต้ lock ทำให้หลาย process แข่งกัน consume ได้</li>
34
+ <li><strong>Self-debouncing</strong> — <code>ourWriteInProgress</code> flag ป้องกัน self-trigger เมื่อเราเป็นคนเขียนเอง</li>
35
+ <li><strong>Cross-platform</strong> — ไฟล์ JSON ทำงานได้ทุก OS ไม่ต้องติดตั้ง message broker</li>
36
+ </ul>
37
+
38
+ <h3>Lease-Based Concurrency — ป้องกัน Task Duplicate</h3>
39
+ <p>ปัญหาคลาสสิกของ distributed workers: มี 2 worker เห็น task เดียวกันและทำงานซ้ำ Lease แก้ปัญหานี้โดยไม่ต้องใช้ distributed lock:</p>
40
+ <pre><code>Main Loop Queue File (.json) Worker Process
41
+ │ │ │
42
+ │ getNextTask() │ │
43
+ │─────────────────────────────►│ │
44
+ │◄─── task {id, status:pending}│ │
45
+ │ │ │
46
+ │ leaseTask(id, agentId) │ │
47
+ │─────────────────────────────►│ │
48
+ │ (atomic: check no lease │ │
49
+ │ → write leaseOwner + │ │
50
+ │ leaseExpiresAt) │ │
51
+ │◄─────── true (leased) ──────│ │
52
+ │ │ │
53
+ │ spawnWorker(prompt) │ │
54
+ │─────────────────────────────────────────────────────────────►│
55
+ │◄──── WorkerSession {id, pid} │ │
56
+ │ │ │
57
+ │ ═══ LOOP ═══ │ │
58
+ │ while running: │ │
59
+ │ checkWorker(sessionId) │ │
60
+ │ ────────────────────────────────────────────────────────►│
61
+ │ ◄─── "running" / "completed" / "failed" │
62
+ │ │ │
63
+ │ │ (worker ทำงาน autonomously) │
64
+ │ │ │
65
+ │ [completed] → releaseLease │ │
66
+ │ → markCompleted │ │
67
+ │ │ │
68
+ │ [failed] → markFailed │ │
69
+ │ → retryTask() │ │
70
+ │ → stopWorker() │ │
71
+ │ │ │
72
+ │ [timeout 30m] → stopWorker │ │
73
+ │ → releaseLease│ │
74
+ │ → retryTask() │ │</code></pre>
75
+ <ul>
76
+ <li><strong>Lease owner</strong> — ระบุว่า worker ไหนกำลังทำ task นี้</li>
77
+ <li><strong>Lease expiry</strong> — ถ้า worker crash โดยไม่ release, lease จะหมดอายุเอง → worker อื่นรับงานต่อได้</li>
78
+ <li><strong>Startup recovery</strong> — ตอน <code>startLoop</code> จะรอ 2 วินาที (ให้ process เก่าตายแน่ๆ) แล้วเรียก <code>expireLeases()</code> ล้าง stale lease ทั้งหมด</li>
79
+ </ul>
80
+
81
+ <h3>Retry with Exponential Backoff</h3>
82
+ <p>Task ที่ fail ไม่ได้แปลว่าต้อง dead-letter ทันที:</p>
83
+ <pre><code>Retry attempt Backoff delay Cumulative wait
84
+ ───────────── ───────────── ──────────────
85
+ 1 base × 2¹ = 30s 30s
86
+ 2 base × 2² = 60s 90s
87
+ 3 base × 2³ = 120s 210s
88
+ 4 base × 2⁴ = 240s 450s
89
+ 5 (max) base × 2⁵ = 480s 930s (~15 min)
90
+
91
+ After max retries → dead_letter queue
92
+ Dead-letter preserves: title, description, lastError, errorLog, retryCount</code></pre>
93
+ <ul>
94
+ <li><strong>Exponential backoff</strong> — base = 15s, factor = 2 — ลดการถล่ม queue เมื่อ task fail ซ้ำๆ</li>
95
+ <li><strong>Max retries</strong> — default 5 ครั้งต่อ task</li>
96
+ <li><strong>Retry interval</strong> — <code>retryAfter</code> timestamp ป้องกันไม่ให้ retry ก่อนเวลาที่กำหนด</li>
97
+ <li><strong>Dead-letter queue</strong> — task ที่ใช้ retry หมดจะถูกย้ายไปสถานะ <code>dead_letter</code> พร้อม <code>deadLetterReason</code> และ <code>errorLog</code> — ไม่หายไปไหน ตรวจสอบย้อนหลังได้</li>
98
+ </ul>
99
+
100
+ <h3>Worker Lifecycle + Concurrent Cap</h3>
101
+ <p>Main loop มีกลไกจำกัดจำนวน worker พร้อมกัน:</p>
102
+ <ul>
103
+ <li><strong>MAX_CONCURRENT_WORKERS = 3</strong> — ป้องกันไม่ให้ spawn worker มากเกินไปจนเครื่องพัง</li>
104
+ <li><strong>Loop poll interval</strong> — ถ้า worker เต็ม → sleep <code>LOOP_SLEEP_MS</code> (5s) แล้วตรวจใหม่</li>
105
+ <li><strong>Worker timeout = 30 นาที</strong> — task ที่รันนานเกินจะถูก kill เพื่อคืน resource</li>
106
+ <li><strong>Worker poll = 10s</strong> — เช็คสถานะ worker ทุก 10 วินาทีผ่าน supervisor IPC</li>
107
+ </ul>
108
+
109
+ <h3>Supervisor Integration — Process Health</h3>
110
+ <p>Worker ไม่ได้ถูกรันโดยตรง แต่ spawn ผ่าน<strong>Supervisor process</strong> (child_process):</p>
111
+ <pre><code>Agent Loop Supervisor Worker
112
+ │ │ │
113
+ │ sendRequest({type:'spawn'}) │ │
114
+ │─────────────────────────────►│ │
115
+ │ │ spawn child_process │
116
+ │ │────────────────────────►│
117
+ │◄─── {ok:true, sessionId, pid}│ │
118
+ │ │ │
119
+ │ sendRequest({type:'attach'}) │ │
120
+ │─────────────────────────────►│ │
121
+ │ │ check process status │
122
+ │◄─── {status, isRunning} │ │
123
+ │ │ │
124
+ │ sendRequest({type:'stop'}) │ │
125
+ │─────────────────────────────►│ │
126
+ │ │ kill + cleanup │
127
+ │ │────────────────────────►│</code></pre>
128
+ <ul>
129
+ <li><strong>Crash isolation</strong> — worker crash ไม่ทำให้ loop crash — supervisor แยก process คนละตัว</li>
130
+ <li><strong>Output capture</strong> — supervisor เก็บ stdout/stderr ของ worker ไว้ใน <code>~/.claude/daemon/jobs/{sessionId}/output.log</code></li>
131
+ <li><strong>Health monitoring</strong> — loop เช็คผ่าน supervisor แทนที่จะ monitor PID โดยตรง (PID reuse problem)</li>
132
+ </ul>
133
+
134
+ <h3>Integration Points — Peer + Cron + Watch</h3>
135
+ <p>Agent Loop ไม่ได้อยู่เดี่ยวๆ — มัน integrate กับระบบอื่นของ Clew:</p>
136
+ <ul>
137
+ <li><strong>Peer todo listener</strong> — ฟัง <code>/peer-todo</code> HTTP endpoint → รับ task จาก remote peer → add เข้า queue</li>
138
+ <li><strong>Cron scheduler</strong> — <code>daemonCronScheduler</code> fire task ตาม schedule → add เข้า queue</li>
139
+ <li><strong>File watcher</strong> — <code>fs.watch</code> บน queue file → ตรวจจับ task ใหม่จาก process อื่น (เช่นจาก CLI <code>/task add</code>)</li>
140
+ </ul>
141
+ <p>architecture แบบนี้ทำให้ task เข้า queue ได้จากหลายช่องทาง — CLI, remote peer, cron — แต่มี consumer เดียว (loop) ที่คุมการ execute</p>
142
+
143
+ <h3>Task Log Persistence</h3>
144
+ <p>ทุก task มี log ของตัวเอง:</p>
145
+ <ul>
146
+ <li><strong>Per-task log</strong> — <code>~/.claude/daemon/logs/{taskId}.log</code> — 500 บรรทัดสุดท้ายของ worker output</li>
147
+ <li><strong>Error extraction</strong> — ตอน task fail, loop จะ extract non-noise lines (20 บรรทัดสุดท้าย) เก็บเป็น <code>errorLog[]</code> ใน queue entry</li>
148
+ <li><strong>Worker exit code</strong> — บันทึกว่า worker จบด้วย exit code 0 (success) หรือ 1 (failure)</li>
149
+ </ul>
150
+
151
+ <h3>Crash Recovery Flow</h3>
152
+ <p>ถ้า loop process ตาย (kill -9, power loss, OOM):</p>
153
+ <pre><code>Previous Run Crash
154
+
155
+
156
+ startLoop() called
157
+
158
+ ├── loadQueue() — อ่านไฟล์ queue จาก disk
159
+
160
+ ├── sleep(2000ms) — รอให้แน่ใจว่า process เก่าตายแล้ว
161
+
162
+ ├── expireLeases() — ล้าง lease ทั้งหมดที่หมดอายุ
163
+ │ (task ที่ถูก lease โดย processID เก่าจะถูก reset → pending)
164
+
165
+ ├── start heartbeat (ทุก 60s)
166
+
167
+ ├── start cron scheduler
168
+
169
+ ├── start peer sharing
170
+
171
+ ├── start file watcher
172
+
173
+ └── MAIN LOOP ──► getNextTask() → processTask() → loop</code></pre>
174
+
175
+ <h2>Task Lifecycle (State Machine)</h2>
176
+ <pre><code> ┌──────────┐
177
+ │ pending │◄──────────────────────────────┐
178
+ └────┬─────┘ │
179
+ │ leaseTask() │
180
+ ▼ │
181
+ ┌──────────┐ │
182
+ │in_progress│ │
183
+ └────┬─────┘ │
184
+ ┌───────────┼───────────┐ │
185
+ ▼ ▼ ▼ │
186
+ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
187
+ │completed │ │ failed │ │cancelled │ │
188
+ └──────────┘ └────┬─────┘ └──────────┘ │
189
+ │ retryTask() │
190
+ ├── retryCount < max → backoff → ────┘
191
+
192
+ └── retryCount ≥ max
193
+
194
+
195
+ ┌──────────────┐
196
+ │ dead_letter │
197
+ │ (preserved │
198
+ │ for review) │
199
+ └──────────────┘</code></pre>
200
+
201
+ <h2>ไฟล์ที่เกี่ยวข้อง</h2>
202
+ <table>
203
+ <tr><th>ไฟล์</th><th>หน้าที่</th></tr>
204
+ <tr><td><code>src/services/autonomous/agentLoop.ts</code></td><td>Main loop — start, stop, processTask, worker lifecycle</td></tr>
205
+ <tr><td><code>src/services/autonomous/taskQueue.ts</code></td><td>Queue CRUD, lease management, retry, dead-letter, file watcher</td></tr>
206
+ <tr><td><code>src/services/autonomous/daemonMode.ts</code></td><td>Daemon entry point — calls startLoop/stopLoop</td></tr>
207
+ <tr><td><code>src/Task.ts</code></td><td>Task type definitions, state machine, task ID generation</td></tr>
208
+ <tr><td><code>src/tasks/LocalAgentTask/</code></td><td>Local worker task — UI + lifecycle</td></tr>
209
+ <tr><td><code>src/tasks/RemoteAgentTask/</code></td><td>Remote worker task — UI + lifecycle</td></tr>
210
+ <tr><td><code>src/components/AutonomousExecutionAccordion.tsx</code></td><td>UI component สำหรับแสดง task queue ใน REPL</td></tr>
211
+ </table>
212
+
213
+ <footer class="footer">
214
+ <span>Clew Code — Open Source</span>
215
+ <div class="footer-links">
216
+ <a href="https://github.com/JonusNattapong/ClewCode">GitHub</a>
217
+ <a href="https://github.com/JonusNattapong/ClewCode/issues">Issues</a>
218
+ </div>
219
+ </footer>
220
+ </main>
221
+ <nav class="toc-sidebar"></nav>
222
+ </div>
223
+ </div>
224
+ <script src="js/main.js"></script>
225
+ </body>
226
+ </html>