Fundamentals
ลูปของเอเจนต์
ลูปแบบเอเจนต์คือการรันเอเจนต์แบบ "จริง" เต็มรูปแบบ: รับเข้า → ประกอบบริบท → อนุมานด้วยโมเดล → เรียกใช้เครื่องมือ → สตรีมคำตอบ → บันทึกคงทน เป็นเส้นทางหลักที่เชื่อถือได้ซึ่งเปลี่ยนข้อความ ให้เป็นการกระทำและคำตอบสุดท้าย พร้อมรักษาสถานะเซสชันให้สอดคล้องกัน
ใน OpenClaw ลูปคือการรันเดี่ยวแบบเรียงลำดับต่อเซสชัน ซึ่งส่งเหตุการณ์วงจรชีวิตและสตรีม ขณะที่โมเดลคิด เรียกเครื่องมือ และสตรีมผลลัพธ์ เอกสารนี้อธิบายว่าลูปจริงนี้ เชื่อมต่อแบบต้นจนจบอย่างไร
จุดเข้าใช้งาน
- Gateway RPC:
agentและagent.wait - CLI: คำสั่ง
agent
วิธีทำงาน (ภาพรวม)
- RPC
agentตรวจสอบ params, resolve session (sessionKey/sessionId), บันทึก metadata ของ session, แล้วคืน{ runId, acceptedAt }ทันที agentCommandรันเอเจนต์:- resolve โมเดล + ค่าเริ่มต้น thinking/verbose/trace
- โหลดสแนปชอต Skills
- เรียก
runEmbeddedPiAgent(runtime ของ pi-agent-core) - ส่ง lifecycle end/error หากลูปแบบฝังไม่ได้ส่งเอง
runEmbeddedPiAgent:- จัดลำดับการรันผ่านคิวต่อเซสชัน + คิวส่วนกลาง
- resolve โมเดล + โปรไฟล์ auth และสร้างเซสชัน Pi
- subscribe เหตุการณ์ Pi และสตรีม delta ของ assistant/tool
- บังคับใช้ timeout -> abort การรันหากเกินเวลา
- สำหรับ turn ของ Codex app-server จะ abort turn ที่รับแล้วซึ่งหยุดสร้างความคืบหน้า app-server ก่อนเหตุการณ์สิ้นสุด
- คืน payloads + metadata การใช้งาน
subscribeEmbeddedPiSessionเชื่อมเหตุการณ์ pi-agent-core ไปยังสตรีมagentของ OpenClaw:- เหตุการณ์ tool =>
stream: "tool" - delta ของ assistant =>
stream: "assistant" - เหตุการณ์ lifecycle =>
stream: "lifecycle"(phase: "start" | "end" | "error")
- เหตุการณ์ tool =>
agent.waitใช้waitForAgentRun:- รอ lifecycle end/error สำหรับ
runId - คืน
{ status: ok|error|timeout, startedAt, endedAt, error? }
- รอ lifecycle end/error สำหรับ
การเข้าคิว + การทำงานพร้อมกัน
- การรันจะถูกจัดลำดับต่อ session key (session lane) และอาจผ่าน global lane ด้วย
- วิธีนี้ป้องกัน race ของ tool/session และรักษาประวัติ session ให้สอดคล้องกัน
- ช่องทางข้อความสามารถเลือกโหมดคิว (collect/steer/followup) ที่ป้อนเข้าระบบ lane นี้ได้ ดู คิวคำสั่ง
- การเขียน transcript ก็ได้รับการป้องกันด้วย session write lock บนไฟล์ session เช่นกัน lock นี้
รับรู้ process และอิงไฟล์ จึงจับ writer ที่ข้ามคิวใน process หรือมาจาก
process อื่นได้ writer ของ session transcript จะรอได้สูงสุด
session.writeLock.acquireTimeoutMsก่อนรายงานว่า session ไม่ว่าง ค่าเริ่มต้นคือ60000ms - session write lock ไม่ใช่ reentrant โดยค่าเริ่มต้น หาก helper ตั้งใจซ้อนการ acquire
lock เดิมขณะยังรักษา writer เชิงตรรกะไว้หนึ่งตัว ต้อง opt in อย่างชัดเจนด้วย
allowReentrant: true
การเตรียม session + workspace
- workspace ถูก resolve และสร้างขึ้น การรันใน sandbox อาจ redirect ไปยัง root ของ sandbox workspace
- Skills ถูกโหลด (หรือใช้ซ้ำจากสแนปชอต) และ inject เข้า env และ prompt
- ไฟล์ bootstrap/context ถูก resolve และ inject เข้า report ของ system prompt
- มีการ acquire session write lock;
SessionManagerถูกเปิดและเตรียมก่อนเริ่มสตรีม เส้นทาง rewrite, compaction หรือ truncation ของ transcript ในภายหลัง ต้องใช้ lock เดียวกันก่อนเปิดหรือ แก้ไขไฟล์ transcript
การประกอบ prompt + system prompt
- system prompt สร้างจาก base prompt ของ OpenClaw, prompt ของ Skills, bootstrap context และ override ต่อการรัน
- บังคับใช้ขีดจำกัดเฉพาะโมเดลและ token สำรองสำหรับ compaction
- ดู system prompt เพื่อดูว่าโมเดลเห็นอะไร
จุด hook (ที่คุณสามารถดักแทรกได้)
OpenClaw มีระบบ hook สองแบบ:
- hook ภายใน (Gateway hooks): สคริปต์แบบ event-driven สำหรับคำสั่งและเหตุการณ์ lifecycle
- Plugin hooks: จุดต่อขยายภายใน lifecycle ของ agent/tool และ gateway pipeline
hook ภายใน (Gateway hooks)
agent:bootstrap: ทำงานขณะสร้างไฟล์ bootstrap ก่อน finalize system prompt ใช้สิ่งนี้เพื่อเพิ่ม/ลบไฟล์ bootstrap context- hook คำสั่ง:
/new,/reset,/stopและเหตุการณ์คำสั่งอื่นๆ (ดูเอกสาร Hooks)
ดู Hooks สำหรับการตั้งค่าและตัวอย่าง
Plugin hooks (lifecycle ของ agent + gateway)
สิ่งเหล่านี้ทำงานภายในลูปเอเจนต์หรือ gateway pipeline:
before_model_resolve: ทำงานก่อน session (ไม่มีmessages) เพื่อ override provider/model อย่างกำหนดซ้ำได้ก่อนการ resolve โมเดลbefore_prompt_build: ทำงานหลังโหลด session (พร้อมmessages) เพื่อ injectprependContext,systemPrompt,prependSystemContextหรือappendSystemContextก่อนส่ง prompt ใช้prependContextสำหรับข้อความ dynamic ต่อ turn และใช้ฟิลด์ system-context สำหรับคำแนะนำที่เสถียรซึ่งควรอยู่ในพื้นที่ system promptbefore_agent_start: hook เพื่อความเข้ากันได้แบบ legacy ที่อาจทำงานใน phase ใดก็ได้; ควรใช้ hook ที่ชัดเจนด้านบนbefore_agent_reply: ทำงานหลัง inline actions และก่อนการเรียก LLM ทำให้ Plugin claim turn และคืน synthetic reply หรือทำให้ turn เงียบทั้งหมดได้agent_end: ตรวจรายการข้อความสุดท้ายและ metadata การรันหลังเสร็จสิ้นbefore_compaction/after_compaction: สังเกตหรือ annotate รอบ compactionbefore_tool_call/after_tool_call: ดักพารามิเตอร์/ผลลัพธ์ของ toolbefore_install: ตรวจ findings จาก built-in scan และอาจบล็อกการติดตั้ง skill หรือ Plugintool_result_persist: transform ผลลัพธ์ tool แบบ synchronous ก่อนเขียนลง session transcript ที่ OpenClaw เป็นเจ้าของmessage_received/message_sending/message_sent: hook ข้อความขาเข้า + ขาออกsession_start/session_end: ขอบเขต lifecycle ของ sessiongateway_start/gateway_stop: เหตุการณ์ lifecycle ของ gateway
กฎการตัดสินใจของ hook สำหรับ guard ขาออก/tool:
before_tool_call:{ block: true }เป็น terminal และหยุด handler ที่ priority ต่ำกว่าbefore_tool_call:{ block: false }เป็น no-op และไม่ล้าง block ก่อนหน้าbefore_install:{ block: true }เป็น terminal และหยุด handler ที่ priority ต่ำกว่าbefore_install:{ block: false }เป็น no-op และไม่ล้าง block ก่อนหน้าmessage_sending:{ cancel: true }เป็น terminal และหยุด handler ที่ priority ต่ำกว่าmessage_sending:{ cancel: false }เป็น no-op และไม่ล้าง cancel ก่อนหน้า
ดู Plugin hooks สำหรับรายละเอียด hook API และการลงทะเบียน
harness อาจปรับ hook เหล่านี้ต่างกัน harness ของ Codex app-server คง OpenClaw plugin hooks ไว้เป็น contract ความเข้ากันได้สำหรับพื้นผิว mirrored ที่จัดทำเอกสารไว้ ขณะที่ Codex native hooks ยังคงเป็นกลไก Codex ระดับล่างที่แยกต่างหาก
การสตรีม + คำตอบบางส่วน
- delta ของ assistant ถูกสตรีมจาก pi-agent-core และส่งเป็นเหตุการณ์
assistant - block streaming สามารถส่งคำตอบบางส่วนได้ทั้งบน
text_endหรือmessage_end - reasoning streaming สามารถส่งเป็นสตรีมแยกต่างหากหรือเป็น block replies
- ดู Streaming สำหรับพฤติกรรม chunking และ block reply
การเรียกใช้เครื่องมือ + เครื่องมือส่งข้อความ
- เหตุการณ์เริ่ม/update/จบของ tool ถูกส่งบนสตรีม
tool - ผลลัพธ์ tool ถูก sanitize ด้านขนาดและ payload รูปภาพก่อน logging/emitting
- การส่งผ่าน messaging tool ถูกติดตามเพื่อกดทับ confirmation ของ assistant ที่ซ้ำกัน
การจัดรูปคำตอบ + การกดทับ
- payload สุดท้ายประกอบจาก:
- ข้อความ assistant (และ reasoning ที่เป็น optional)
- summary ของ inline tool (เมื่อ verbose + allowed)
- ข้อความ error ของ assistant เมื่อโมเดล error
- token เงียบแบบตรงตัว
NO_REPLY/no_replyถูกกรองออกจาก payload ขาออก - messaging tool ที่ซ้ำกันถูกลบออกจากรายการ payload สุดท้าย
- หากไม่มี payload ที่ render ได้เหลืออยู่และ tool เกิด error จะส่ง fallback tool error reply (เว้นแต่ว่า messaging tool ได้ส่งคำตอบที่ผู้ใช้มองเห็นไปแล้ว)
Compaction + การลองใหม่
- auto-compaction ส่งเหตุการณ์สตรีม
compactionและสามารถ trigger การลองใหม่ - เมื่อ retry buffer ในหน่วยความจำและ summary ของ tool จะถูก reset เพื่อหลีกเลี่ยง output ซ้ำ
- ดู Compaction สำหรับ pipeline ของ compaction
สตรีมเหตุการณ์ (ปัจจุบัน)
lifecycle: ส่งโดยsubscribeEmbeddedPiSession(และส่งเป็น fallback โดยagentCommand)assistant: delta ที่สตรีมจาก pi-agent-coretool: เหตุการณ์ tool ที่สตรีมจาก pi-agent-core
การจัดการช่องทางแชต
- delta ของ assistant ถูก buffer เป็นข้อความ
deltaของแชต finalของแชตถูกส่งเมื่อ lifecycle end/error
timeout
- ค่าเริ่มต้นของ
agent.wait: 30s (เฉพาะการรอ) พารามิเตอร์timeoutMsoverride ได้ - runtime ของ agent: ค่าเริ่มต้น
agents.defaults.timeoutSeconds172800s (48 ชั่วโมง); บังคับใช้ใน abort timer ของrunEmbeddedPiAgent - runtime ของ Cron:
timeoutSecondsของ agent-turn แบบ isolated เป็นของ cron scheduler เริ่ม timer นั้นเมื่อการ execute เริ่มขึ้น, abort run ที่อยู่ข้างใต้เมื่อถึง deadline ที่กำหนดค่าไว้, แล้วทำ cleanup แบบมีขอบเขตก่อนบันทึก timeout เพื่อให้ child session ที่ stale ไม่ทำให้ lane ค้างอยู่ - diagnostics ความยังทำงานของ session: เมื่อเปิด diagnostics,
diagnostics.stuckSessionWarnMsจะจำแนก sessionprocessingที่ยาวนานซึ่งไม่มี reply, tool, status, block หรือความคืบหน้า ACP ที่สังเกตได้ การรันแบบ embedded ที่ active, การเรียกโมเดล และการเรียก tool จะรายงานเป็นsession.long_running; งานที่ active แต่ไม่มีความคืบหน้าล่าสุดจะรายงานเป็นsession.stalled;session.stuckสงวนไว้สำหรับ bookkeeping ของ session ที่ stale โดยไม่มีงาน active bookkeeping ของ session ที่ stale จะปล่อย session lane ที่ได้รับผลกระทบทันที; embedded run ที่ stalled จะถูก abort-drain หลังจากdiagnostics.stuckSessionAbortMsเท่านั้น (ค่าเริ่มต้น: อย่างน้อย 10 นาทีและ 5 เท่าของ threshold การเตือน) เพื่อให้งานที่เข้าคิวกลับมาทำต่อได้โดยไม่ตัดการรันที่เพียงแค่ช้าออก Recovery ส่ง outcome requested/completed แบบมีโครงสร้าง และสถานะ diagnostic จะถูกทำเครื่องหมาย idle เฉพาะเมื่อ processing generation เดิมยัง current อยู่เท่านั้น diagnosticssession.stuckที่ซ้ำจะ back off ขณะที่ session ยังไม่เปลี่ยนแปลง - model idle timeout: OpenClaw abort request ของโมเดลเมื่อไม่มี response chunk มาถึงก่อน idle window
models.providers.<id>.timeoutSecondsขยาย idle watchdog นี้สำหรับ provider แบบ local/self-hosted ที่ช้า; มิฉะนั้น OpenClaw ใช้agents.defaults.timeoutSecondsเมื่อกำหนดค่าไว้ โดย capped ที่ 120s ตามค่าเริ่มต้น การรันที่ trigger โดย Cron และไม่มี timeout ของโมเดลหรือ agent ที่ explicit จะปิด idle watchdog และพึ่ง timeout ชั้นนอกของ cron - timeout ของ HTTP request ของ provider:
models.providers.<id>.timeoutSecondsใช้กับ model HTTP fetches ของ provider นั้น รวมถึง connect, headers, body, SDK request timeout, การจัดการ abort ของ guarded-fetch ทั้งหมด และ model stream idle watchdog ใช้ค่านี้สำหรับ provider แบบ local/self-hosted ที่ช้า เช่น Ollama ก่อนเพิ่ม timeout runtime ของ agent ทั้งหมด
จุดที่สิ่งต่างๆ อาจจบก่อนกำหนด
- timeout ของ agent (abort)
- AbortSignal (cancel)
- Gateway disconnect หรือ RPC timeout
- timeout ของ
agent.wait(เฉพาะการรอ ไม่หยุด agent)
ที่เกี่ยวข้อง
- Tools — เครื่องมือ agent ที่มีให้ใช้
- Hooks — สคริปต์ event-driven ที่ trigger โดยเหตุการณ์ lifecycle ของ agent
- Compaction — วิธีสรุปบทสนทนายาวๆ
- Exec Approvals — approval gates สำหรับคำสั่ง shell
- Thinking — การกำหนดค่าระดับ thinking/reasoning