clew-code 0.2.13 → 0.2.14
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/dist/main.js +2596 -2527
- package/docs/architecture.html +148 -148
- package/docs/architecture.th.html +79 -79
- package/docs/clew-code-architecture.html +6 -6
- package/docs/commands.html +225 -224
- package/docs/commands.th.html +132 -131
- package/docs/configuration.html +147 -147
- package/docs/configuration.th.html +108 -108
- package/docs/daemon.html +129 -129
- package/docs/daemon.th.html +73 -73
- package/docs/features/bridge-mode.html +99 -99
- package/docs/features/bridge-mode.th.html +90 -90
- package/docs/features/evals.html +182 -182
- package/docs/features/evals.th.html +90 -90
- package/docs/features/peer.html +178 -178
- package/docs/features/searxng-search.html +151 -151
- package/docs/features/searxng-search.th.html +95 -95
- package/docs/features/sentry-setup.html +157 -157
- package/docs/features/sentry-setup.th.html +97 -97
- package/docs/index.html +298 -299
- package/docs/index.th.html +292 -292
- package/docs/installation.html +105 -105
- package/docs/installation.th.html +105 -105
- package/docs/internals/growthbook-ab-testing.html +113 -113
- package/docs/internals/growthbook-ab-testing.th.html +81 -81
- package/docs/internals/hidden-features.html +175 -149
- package/docs/internals/hidden-features.th.html +135 -109
- package/docs/loop.html +181 -181
- package/docs/loop.th.html +227 -227
- package/docs/mcp.html +247 -247
- package/docs/mcp.th.html +207 -207
- package/docs/models.html +110 -111
- package/docs/models.th.html +61 -61
- package/docs/peer.html +236 -236
- package/docs/peer.th.html +280 -280
- package/docs/permission-model.html +102 -102
- package/docs/permission-model.th.html +67 -67
- package/docs/plugins.html +102 -102
- package/docs/plugins.th.html +79 -79
- package/docs/providers.html +126 -126
- package/docs/providers.th.html +80 -80
- package/docs/quick-start.html +93 -93
- package/docs/quick-start.th.html +1 -1
- package/docs/research-memory.html +82 -82
- package/docs/research-memory.th.html +72 -72
- package/docs/skills.html +117 -117
- package/docs/skills.th.html +90 -90
- package/docs/tools.html +170 -170
- package/docs/tools.th.html +84 -84
- package/docs/troubleshooting.html +106 -106
- package/docs/troubleshooting.th.html +85 -85
- package/package.json +162 -164
package/docs/loop.th.html
CHANGED
|
@@ -1,227 +1,227 @@
|
|
|
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/ClewCode/ClewCode">GitHub</a>
|
|
217
|
-
<a href="https://github.com/ClewCode/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>
|
|
227
|
-
|
|
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/ClewCode/ClewCode">GitHub</a>
|
|
217
|
+
<a href="https://github.com/ClewCode/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>
|
|
227
|
+
|