56 KiB
| read_when | sidebarTitle | summary | title | x-i18n | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Sub-agents | สร้างการรันเอเจนต์พื้นหลังแบบแยกอิสระ ซึ่งประกาศผลลัพธ์กลับไปยังแชตของผู้ร้องขอ | เอเจนต์ย่อย |
|
เอเจนต์ย่อยคือการรันเอเจนต์เบื้องหลังที่ถูกสร้างจากการรันเอเจนต์ที่มีอยู่
เอเจนต์เหล่านี้รันในเซสชันของตัวเอง (agent:<agentId>:subagent:<uuid>) และ
เมื่อเสร็จสิ้น จะประกาศผลลัพธ์กลับไปยังช่องแชตของผู้ร้องขอ
การรันเอเจนต์ย่อยแต่ละครั้งจะถูกติดตามเป็น
งานเบื้องหลัง
เป้าหมายหลัก:
- ทำให้งาน "วิจัย / งานยาว / เครื่องมือที่ช้า" รันแบบขนานได้โดยไม่บล็อกการรันหลัก
- แยกเอเจนต์ย่อยออกจากกันตามค่าเริ่มต้น (การแยกเซสชัน + sandboxing แบบเลือกได้)
- ทำให้พื้นผิวเครื่องมือใช้งานผิดได้ยาก: เอเจนต์ย่อยจะไม่ได้รับเครื่องมือเซสชันตามค่าเริ่มต้น
- รองรับความลึกของการซ้อนที่กำหนดค่าได้สำหรับรูปแบบ orchestrator
คำสั่ง slash
ใช้ /subagents เพื่อตรวจสอบหรือควบคุมการรันเอเจนต์ย่อยสำหรับเซสชันปัจจุบัน:
/subagents list
/subagents kill <id|#|all>
/subagents log <id|#> [limit] [tools]
/subagents info <id|#>
/subagents send <id|#> <message>
/subagents steer <id|#> <message>
/subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]
ใช้ /steer <message> ระดับบนสุดเพื่อ steer การรันที่ใช้งานอยู่ของเซสชันผู้ร้องขอปัจจุบัน ใช้ /subagents steer <id|#> <message> เมื่อเป้าหมายเป็นการรันลูก
/subagents info แสดงข้อมูลเมตาของการรัน (สถานะ, timestamp, id เซสชัน,
พาธ transcript, cleanup) ใช้ sessions_history สำหรับมุมมองการเรียกดูย้อนหลังที่มีขอบเขตและผ่านการกรองความปลอดภัยแล้ว; ตรวจสอบพาธ transcript บนดิสก์เมื่อคุณต้องการ transcript ฉบับเต็มแบบดิบ
การควบคุมการผูกเธรด
คำสั่งเหล่านี้ทำงานบนช่องที่รองรับการผูกเธรดแบบคงอยู่ ดู ช่องที่รองรับเธรด ด้านล่าง
/focus <subagent-label|session-key|session-id|session-label>
/unfocus
/agents
/session idle <duration|off>
/session max-age <duration|off>
พฤติกรรมการ spawn
/subagents spawn เริ่มเอเจนต์ย่อยเบื้องหลังในฐานะคำสั่งของผู้ใช้ (ไม่ใช่ relay ภายใน) และส่งการอัปเดตการเสร็จสิ้นขั้นสุดท้ายหนึ่งครั้งกลับไปยังแชตของผู้ร้องขอเมื่อการรันเสร็จสิ้น
- `Result` — ข้อความตอบกลับ `assistant` ที่มองเห็นล่าสุด มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ sanitize แล้ว การรันที่ล้มเหลวแบบสิ้นสุดจะไม่นำข้อความตอบกลับที่จับไว้กลับมาใช้ซ้ำ
- `Status` — `completed successfully` / `failed` / `timed out` / `unknown`
- สถิติ runtime/token แบบย่อ
- คำสั่งการส่งมอบที่บอกเอเจนต์ผู้ร้องขอให้เขียนใหม่ด้วยเสียง assistant ปกติ (ไม่ส่งต่อ metadata ภายในแบบดิบ)
- `--model` และ `--thinking` override ค่าเริ่มต้นสำหรับการรันนั้นโดยเฉพาะ
- ใช้ `info`/`log` เพื่อตรวจสอบรายละเอียดและเอาต์พุตหลังเสร็จสิ้น
- `/subagents spawn` เป็นโหมด one-shot (`mode: "run"`) สำหรับเซสชันแบบคงอยู่ที่ผูกกับเธรด ให้ใช้ `sessions_spawn` พร้อม `thread: true` และ `mode: "session"`
- สำหรับเซสชัน harness ของ ACP (Claude Code, Gemini CLI, OpenCode, หรือ Codex ACP/acpx ที่ระบุชัดเจน) ให้ใช้ `sessions_spawn` พร้อม `runtime: "acp"` เมื่อเครื่องมือประกาศ runtime นั้น ดู [โมเดลการส่งมอบของ ACP](/th/tools/acp-agents#delivery-model) เมื่อดีบักการเสร็จสิ้นหรือลูป agent-to-agent เมื่อเปิดใช้งาน Plugin `codex` การควบคุมแชต/เธรดของ Codex ควรเลือกใช้ `/codex ...` แทน ACP เว้นแต่ผู้ใช้จะขอ ACP/acpx อย่างชัดเจน
- OpenClaw ซ่อน `runtime: "acp"` จนกว่า ACP จะเปิดใช้งาน ผู้ร้องขอไม่ได้อยู่ใน sandbox และมีการโหลด Plugin backend เช่น `acpx` แล้ว `runtime: "acp"` คาดหวัง id harness ACP ภายนอก หรือรายการ `agents.list[]` ที่มี `runtime.type="acp"`; ใช้ runtime เอเจนต์ย่อยค่าเริ่มต้นสำหรับเอเจนต์ config ของ OpenClaw ปกติจาก `agents_list`
โหมดบริบท
เอเจนต์ย่อยแบบ native จะเริ่มแบบแยกเดี่ยว เว้นแต่ผู้เรียกจะขอ fork transcript ปัจจุบันอย่างชัดเจน
| โหมด | ควรใช้เมื่อใด | พฤติกรรม |
|---|---|---|
isolated |
การวิจัยใหม่, การ implementation อิสระ, งานเครื่องมือที่ช้า, หรือสิ่งใดก็ตามที่สามารถสรุปในข้อความงานได้ | สร้าง transcript ลูกที่สะอาด นี่คือค่าเริ่มต้นและช่วยลดการใช้โทเค็น |
fork |
งานที่ขึ้นกับบทสนทนาปัจจุบัน, ผลลัพธ์เครื่องมือก่อนหน้า, หรือคำสั่งที่ละเอียดอ่อนซึ่งมีอยู่แล้วใน transcript ของผู้ร้องขอ | แตกกิ่ง transcript ของผู้ร้องขอไปยังเซสชันลูกก่อนที่ลูกจะเริ่ม |
ใช้ fork อย่างประหยัด มีไว้สำหรับการมอบหมายงานที่อ่อนไหวต่อบริบท ไม่ใช่
สิ่งทดแทนการเขียน prompt งานที่ชัดเจน
เครื่องมือ: sessions_spawn
เริ่มการรันเอเจนต์ย่อยด้วย deliver: false บน lane subagent ระดับ global
จากนั้นรันขั้นตอนประกาศและโพสต์คำตอบประกาศไปยังช่องแชตของผู้ร้องขอ
ความพร้อมใช้งานขึ้นอยู่กับนโยบายเครื่องมือที่มีผลของผู้เรียก โปรไฟล์ coding และ
full เปิดเผย sessions_spawn ตามค่าเริ่มต้น โปรไฟล์ messaging
ไม่เปิดเผย; เพิ่ม tools.alsoAllow: ["sessions_spawn", "sessions_yield", "subagents"] หรือใช้ tools.profile: "coding" สำหรับเอเจนต์ที่ควรมอบหมายงานได้
นโยบาย allow/deny ของ channel/group, provider, sandbox และรายเอเจนต์ยังสามารถ
ลบเครื่องมือนี้หลังขั้นตอนโปรไฟล์ได้ ใช้ /tools จากเซสชันเดียวกันเพื่อยืนยันรายการเครื่องมือที่มีผล
ค่าเริ่มต้น:
- โมเดล: สืบทอดจากผู้เรียก เว้นแต่คุณตั้ง
agents.defaults.subagents.model(หรือagents.list[].subagents.modelรายเอเจนต์);sessions_spawn.modelที่ระบุชัดเจนยังคงชนะ - Thinking: สืบทอดจากผู้เรียก เว้นแต่คุณตั้ง
agents.defaults.subagents.thinking(หรือagents.list[].subagents.thinkingรายเอเจนต์);sessions_spawn.thinkingที่ระบุชัดเจนยังคงชนะ - ระยะหมดเวลาการรัน: หากละ
sessions_spawn.runTimeoutSeconds, OpenClaw จะใช้agents.defaults.subagents.runTimeoutSecondsเมื่อมีการตั้งค่าไว้; มิฉะนั้นจะ fallback เป็น0(ไม่มี timeout)
พารามิเตอร์เครื่องมือ
คำอธิบายงานสำหรับเอเจนต์ย่อย ป้ายกำกับที่มนุษย์อ่านได้แบบเลือกได้ Spawn ภายใต้ id เอเจนต์อื่นเมื่อ `subagents.allowAgents` อนุญาต `acp` ใช้เฉพาะสำหรับ harness ACP ภายนอก (`claude`, `droid`, `gemini`, `opencode`, หรือ Codex ACP/acpx ที่ร้องขออย่างชัดเจน) และสำหรับรายการ `agents.list[]` ที่ `runtime.type` เป็น `acp` เฉพาะ ACP Resume เซสชัน harness ACP ที่มีอยู่เมื่อ `runtime: "acp"`; ถูกละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native เฉพาะ ACP สตรีมเอาต์พุตการรัน ACP ไปยังเซสชันแม่เมื่อ `runtime: "acp"`; ละเว้นสำหรับการ spawn เอเจนต์ย่อยแบบ native Override โมเดลเอเจนต์ย่อย ค่าที่ไม่ถูกต้องจะถูกข้ามและเอเจนต์ย่อยจะรันบนโมเดลค่าเริ่มต้นพร้อมคำเตือนในผลลัพธ์เครื่องมือ Override ระดับ thinking สำหรับการรันเอเจนต์ย่อย ค่าเริ่มต้นเป็น `agents.defaults.subagents.runTimeoutSeconds` เมื่อมีการตั้งค่า มิฉะนั้นเป็น `0` เมื่อมีการตั้งค่า การรันเอเจนต์ย่อยจะถูก abort หลัง N วินาที เมื่อเป็น `true` จะขอการผูกเธรดของช่องสำหรับเซสชันเอเจนต์ย่อยนี้ หากละ `thread: true` และ `mode` ค่าเริ่มต้นจะกลายเป็น `session` `mode: "session"` ต้องใช้ `thread: true` `"delete"` archive ทันทีหลังประกาศ (ยังคงเก็บ transcript ไว้ผ่านการเปลี่ยนชื่อ) `require` ปฏิเสธการ spawn เว้นแต่ runtime ลูกเป้าหมายอยู่ใน sandbox `fork` แตกกิ่ง transcript ปัจจุบันของผู้ร้องขอไปยังเซสชันลูก เอเจนต์ย่อยแบบ native เท่านั้น การ spawn ที่ผูกกับเธรดมีค่าเริ่มต้นเป็น `fork`; การ spawn ที่ไม่ใช่เธรดมีค่าเริ่มต้นเป็น `isolated` `sessions_spawn` ไม่รับพารามิเตอร์การส่งมอบผ่านช่อง (`target`, `channel`, `to`, `threadId`, `replyTo`, `transport`) สำหรับการส่งมอบ ให้ใช้ `message`/`sessions_send` จากการรันที่ spawn แล้วเซสชันที่ผูกกับเธรด
เมื่อเปิดใช้งานการผูกเธรดสำหรับช่อง เอเจนต์ย่อยสามารถคงการผูกกับเธรดไว้ได้ เพื่อให้ข้อความผู้ใช้ติดตามผลในเธรดนั้นยัง route ไปยังเซสชันเอเจนต์ย่อยเดียวกัน
ช่องที่รองรับเธรด
Discord เป็นช่องเดียวที่รองรับอยู่ในปัจจุบัน รองรับ
เซสชัน subagent แบบคงอยู่ที่ผูกกับเธรด (sessions_spawn พร้อม
thread: true), การควบคุมเธรดด้วยตนเอง (/focus, /unfocus, /agents,
/session idle, /session max-age) และคีย์ adapter
channels.discord.threadBindings.enabled,
channels.discord.threadBindings.idleHours,
channels.discord.threadBindings.maxAgeHours, และ
channels.discord.threadBindings.spawnSessions
โฟลว์ด่วน
`sessions_spawn` พร้อม `thread: true` (และ `mode: "session"` แบบเลือกได้) OpenClaw สร้างหรือผูกเธรดกับ target ของเซสชันนั้นในช่องที่ใช้งานอยู่ การตอบกลับและข้อความติดตามผลในเธรดนั้น route ไปยังเซสชันที่ผูกไว้ ใช้ `/session idle` เพื่อตรวจสอบ/อัปเดต auto-unfocus เมื่อไม่มีความเคลื่อนไหว และ `/session max-age` เพื่อควบคุม hard cap ใช้ `/unfocus` เพื่อ detach ด้วยตนเองการควบคุมด้วยตนเอง
| คำสั่ง | ผลลัพธ์ |
|---|---|
/focus <target> |
ผูกเธรดปัจจุบัน (หรือสร้างเธรดใหม่) เข้ากับเป้าหมายเอเจนต์ย่อย/เซสชัน |
/unfocus |
ลบการผูกสำหรับเธรดที่ถูกผูกอยู่ในปัจจุบัน |
/agents |
แสดงรายการงานที่ทำงานอยู่และสถานะการผูก (thread:<id> หรือ unbound) |
/session idle |
ตรวจสอบ/อัปเดตการยกเลิกโฟกัสอัตโนมัติเมื่อไม่ได้ใช้งาน (เฉพาะเธรดที่ถูกผูกและโฟกัสอยู่) |
/session max-age |
ตรวจสอบ/อัปเดตขีดจำกัดสูงสุดแบบบังคับ (เฉพาะเธรดที่ถูกผูกและโฟกัสอยู่) |
สวิตช์การกำหนดค่า
- ค่าเริ่มต้นทั่วระบบ:
session.threadBindings.enabled,session.threadBindings.idleHours,session.threadBindings.maxAgeHours. - คีย์แทนที่ระดับช่องทางและคีย์ผูกอัตโนมัติเมื่อสร้าง ขึ้นอยู่กับอะแดปเตอร์ ดู ช่องทางที่รองรับเธรด ด้านบน
ดู ข้อมูลอ้างอิงการกำหนดค่า และ คำสั่ง Slash สำหรับรายละเอียดอะแดปเตอร์ปัจจุบัน
รายการที่อนุญาต
รายการ ID เอเจนต์ที่สามารถกำหนดเป็นเป้าหมายผ่าน `agentId` แบบชัดเจน (`["*"]` อนุญาตทุกรายการ) ค่าเริ่มต้น: เฉพาะเอเจนต์ผู้ร้องขอ หากคุณตั้งค่ารายการและยังต้องการให้ผู้ร้องขอสร้างตัวเองด้วย `agentId` ให้ใส่ ID ของผู้ร้องขอไว้ในรายการ รายการเอเจนต์เป้าหมายเริ่มต้นที่อนุญาต ซึ่งใช้เมื่อเอเจนต์ผู้ร้องขอไม่ได้ตั้งค่า `subagents.allowAgents` ของตัวเอง บล็อกการเรียก `sessions_spawn` ที่ละ `agentId` (บังคับให้เลือกโปรไฟล์อย่างชัดเจน) การแทนที่รายเอเจนต์: `agents.list[].subagents.requireAgentId`หากเซสชันของผู้ร้องขออยู่ใน sandbox, sessions_spawn จะปฏิเสธเป้าหมาย
ที่จะทำงานแบบไม่อยู่ใน sandbox
การค้นหา
ใช้ agents_list เพื่อดูว่า ID เอเจนต์ใดได้รับอนุญาตสำหรับ
sessions_spawn อยู่ในขณะนี้ การตอบกลับมีโมเดลที่มีผลจริงของเอเจนต์แต่ละรายการ
และเมทาดาทารันไทม์ที่ฝังอยู่ เพื่อให้ผู้เรียกแยกแยะ PI, เซิร์ฟเวอร์แอป Codex
และรันไทม์เนทีฟอื่นที่กำหนดค่าไว้ได้
การเก็บถาวรอัตโนมัติ
- เซสชันเอเจนต์ย่อยจะถูกเก็บถาวรโดยอัตโนมัติหลังจาก
agents.defaults.subagents.archiveAfterMinutes(ค่าเริ่มต้น60) - การเก็บถาวรใช้
sessions.deleteและเปลี่ยนชื่อทรานสคริปต์เป็น*.deleted.<timestamp>(โฟลเดอร์เดียวกัน) cleanup: "delete"จะเก็บถาวรทันทีหลังประกาศ (ยังคงเก็บทรานสคริปต์ไว้ผ่านการเปลี่ยนชื่อ)- การเก็บถาวรอัตโนมัติเป็นแบบ best-effort; ตัวจับเวลาที่ค้างอยู่จะหายไปหาก Gateway รีสตาร์ท
runTimeoutSecondsจะไม่เก็บถาวรอัตโนมัติ; จะหยุดเฉพาะงานที่ทำงานอยู่เท่านั้น เซสชันยังคงอยู่จนกว่าจะเก็บถาวรอัตโนมัติ- การเก็บถาวรอัตโนมัติใช้กับเซสชันระดับความลึก 1 และระดับความลึก 2 เท่ากัน
- การล้างเบราว์เซอร์แยกจากการล้างการเก็บถาวร: แท็บ/โปรเซสของเบราว์เซอร์ที่ติดตามไว้จะถูกปิดแบบ best-effort เมื่องานทำงานเสร็จ แม้จะเก็บระเบียนทรานสคริปต์/เซสชันไว้ก็ตาม
เอเจนต์ย่อยแบบซ้อนกัน
ตามค่าเริ่มต้น เอเจนต์ย่อยไม่สามารถสร้างเอเจนต์ย่อยของตัวเองได้
(maxSpawnDepth: 1) ตั้งค่า maxSpawnDepth: 2 เพื่อเปิดใช้การซ้อนหนึ่งระดับ
นั่นคือ รูปแบบตัวประสานงาน: หลัก → เอเจนต์ย่อยตัวประสานงาน →
เอเจนต์ย่อยของเอเจนต์ย่อยที่เป็นผู้ปฏิบัติงาน
{
agents: {
defaults: {
subagents: {
maxSpawnDepth: 2, // allow sub-agents to spawn children (default: 1)
maxChildrenPerAgent: 5, // max active children per agent session (default: 5)
maxConcurrent: 8, // global concurrency lane cap (default: 8)
runTimeoutSeconds: 900, // default timeout for sessions_spawn when omitted (0 = no timeout)
},
},
},
}
ระดับความลึก
| ความลึก | รูปแบบคีย์เซสชัน | บทบาท | สร้างได้หรือไม่ |
|---|---|---|---|
| 0 | agent:<id>:main |
เอเจนต์หลัก | เสมอ |
| 1 | agent:<id>:subagent:<uuid> |
เอเจนต์ย่อย (ตัวประสานงานเมื่ออนุญาตความลึก 2) | เฉพาะเมื่อ maxSpawnDepth >= 2 |
| 2 | agent:<id>:subagent:<uuid>:subagent:<uuid> |
เอเจนต์ย่อยของเอเจนต์ย่อย (ผู้ปฏิบัติงานปลายทาง) | ไม่เคย |
ลำดับการประกาศ
ผลลัพธ์ไหลย้อนกลับขึ้นตามลำดับ:
- ผู้ปฏิบัติงานระดับความลึก 2 เสร็จสิ้น → ประกาศไปยังพาเรนต์ของตัวเอง (ตัวประสานงานระดับความลึก 1)
- ตัวประสานงานระดับความลึก 1 ได้รับประกาศ สังเคราะห์ผลลัพธ์ เสร็จสิ้น → ประกาศไปยังหลัก
- เอเจนต์หลักได้รับประกาศและส่งให้ผู้ใช้
แต่ละระดับเห็นเฉพาะประกาศจากลูกโดยตรงของตัวเองเท่านั้น
**คำแนะนำด้านการปฏิบัติการ:** เริ่มงานลูกหนึ่งครั้งและรอเหตุการณ์เสร็จสิ้น แทนการสร้างลูปโพลรอบ `sessions_list`, `sessions_history`, `/subagents list` หรือคำสั่ง sleep ของ `exec` `sessions_list` และ `/subagents list` จะคงความสัมพันธ์เซสชันลูก ให้โฟกัสกับงานสด ลูกที่ยังทำงานอยู่ยังคงแนบอยู่ ลูกที่จบแล้วจะยัง มองเห็นได้ในหน้าต่างรายการล่าสุดช่วงสั้น ๆ และลิงก์ลูกที่มีเฉพาะในสโตร์และเก่าแล้วจะ ถูกละเว้นหลังจากหน้าต่างความสดใหม่ของมัน วิธีนี้ป้องกันไม่ให้เมทาดาทา `spawnedBy` / `parentSessionKey` เก่าชุบชีวิตลูกเงาหลัง รีสตาร์ท หากเหตุการณ์เสร็จสิ้นของลูกมาถึงหลังจากคุณส่ง คำตอบสุดท้ายแล้ว การติดตามผลที่ถูกต้องคือโทเคนเงียบตามตัวอักษร `NO_REPLY` / `no_reply`นโยบายเครื่องมือตามความลึก
- บทบาทและขอบเขตการควบคุมถูกเขียนลงในเมทาดาทาเซสชันตอนสร้าง ซึ่งทำให้คีย์เซสชันแบบแบนหรือที่กู้คืนมาไม่สามารถได้สิทธิ์ตัวประสานงานกลับคืนโดยไม่ตั้งใจ
- ความลึก 1 (ตัวประสานงาน เมื่อ
maxSpawnDepth >= 2): ได้รับsessions_spawn,subagents,sessions_list,sessions_historyเพื่อให้จัดการลูกของตัวเองได้ เครื่องมือเซสชัน/ระบบอื่นยังคงถูกปฏิเสธ - ความลึก 1 (ปลายทาง เมื่อ
maxSpawnDepth == 1): ไม่มีเครื่องมือเซสชัน (พฤติกรรมเริ่มต้นปัจจุบัน) - ความลึก 2 (ผู้ปฏิบัติงานปลายทาง): ไม่มีเครื่องมือเซสชัน —
sessions_spawnถูกปฏิเสธเสมอที่ความลึก 2 ไม่สามารถสร้างลูกต่อได้
ขีดจำกัดการสร้างรายเอเจนต์
แต่ละเซสชันเอเจนต์ (ทุกระดับความลึก) มีลูกที่ทำงานอยู่ได้สูงสุด maxChildrenPerAgent
(ค่าเริ่มต้น 5) ในแต่ละครั้ง วิธีนี้ป้องกันการกระจายงานเกินควบคุม
จากตัวประสานงานเดียว
การหยุดแบบลูกโซ่
การหยุดตัวประสานงานระดับความลึก 1 จะหยุดลูกระดับความลึก 2 ทั้งหมดของมันโดยอัตโนมัติ:
/stopในแชตหลักหยุดเอเจนต์ระดับความลึก 1 ทั้งหมดและหยุดแบบลูกโซ่ไปยังลูกระดับความลึก 2 ของพวกเขา/subagents kill <id>หยุดเอเจนต์ย่อยที่ระบุและหยุดแบบลูกโซ่ไปยังลูกของมัน/subagents kill allหยุดเอเจนต์ย่อยทั้งหมดสำหรับผู้ร้องขอและหยุดแบบลูกโซ่
การยืนยันตัวตน
การยืนยันตัวตนของเอเจนต์ย่อยถูกแก้ตาม ID เอเจนต์ ไม่ใช่ตามประเภทเซสชัน:
- คีย์เซสชันเอเจนต์ย่อยคือ
agent:<agentId>:subagent:<uuid> - สโตร์การยืนยันตัวตนถูกโหลดจาก
agentDirของเอเจนต์นั้น - โปรไฟล์การยืนยันตัวตนของเอเจนต์หลักถูกผสานเข้าเป็น fallback; โปรไฟล์เอเจนต์จะแทนที่โปรไฟล์หลักเมื่อมีข้อขัดแย้ง
การผสานเป็นแบบเพิ่มเข้าไป ดังนั้นโปรไฟล์หลักจึงพร้อมใช้งานเป็น fallback เสมอ ยังไม่รองรับการยืนยันตัวตนแบบแยกขาดต่อเอเจนต์อย่างสมบูรณ์
การประกาศ
เอเจนต์ย่อยรายงานกลับผ่านขั้นตอนประกาศ:
- ขั้นตอนประกาศทำงานภายในเซสชันเอเจนต์ย่อย (ไม่ใช่เซสชันผู้ร้องขอ)
- หากเอเจนต์ย่อยตอบกลับตรงกับ
ANNOUNCE_SKIPจะไม่มีการโพสต์อะไร - หากข้อความผู้ช่วยล่าสุดเป็นโทเคนเงียบตรงตัว
NO_REPLY/no_replyเอาต์พุตประกาศจะถูกระงับ แม้จะเคยมีความคืบหน้าที่มองเห็นได้ก่อนหน้านั้น
การส่งมอบขึ้นอยู่กับความลึกของผู้ร้องขอ:
- เซสชันผู้ร้องขอระดับบนสุดใช้การเรียก
agentแบบติดตามผลพร้อมการส่งมอบภายนอก (deliver=true) - เซสชันเอเจนต์ย่อยผู้ร้องขอแบบซ้อนกันจะได้รับการฉีดติดตามผลภายใน (
deliver=false) เพื่อให้ตัวประสานงานสังเคราะห์ผลลัพธ์ลูกภายในเซสชันได้ - หากเซสชันเอเจนต์ย่อยผู้ร้องขอแบบซ้อนกันหายไป OpenClaw จะ fallback ไปยังผู้ร้องขอของเซสชันนั้นเมื่อมี
สำหรับเซสชันผู้ร้องขอระดับบนสุด การส่งมอบโดยตรงในโหมดเสร็จสิ้นจะ แก้เส้นทางบทสนทนา/เธรดที่ถูกผูกและการแทนที่ของ hook ก่อน จากนั้นเติม ฟิลด์เป้าหมายช่องทางที่หายไปจากเส้นทางที่เซสชันผู้ร้องขอเก็บไว้ วิธีนี้ทำให้การเสร็จสิ้นอยู่ในแชต/หัวข้อที่ถูกต้อง แม้ต้นทางการเสร็จสิ้น จะระบุเฉพาะช่องทางก็ตาม
การรวมผลการเสร็จสิ้นของลูกถูกจำกัดขอบเขตไว้ที่งานผู้ร้องขอปัจจุบันเมื่อ สร้างข้อค้นพบการเสร็จสิ้นแบบซ้อนกัน เพื่อป้องกันไม่ให้เอาต์พุตลูกจากงานก่อนหน้า ที่เก่าแล้วรั่วไหลเข้าไปในการประกาศปัจจุบัน การตอบกลับประกาศจะคง การกำหนดเส้นทางเธรด/หัวข้อเมื่อมีในอะแดปเตอร์ช่องทาง
บริบทประกาศ
บริบทประกาศถูกทำให้เป็นมาตรฐานเป็นบล็อกเหตุการณ์ภายในที่เสถียร:
| ฟิลด์ | แหล่งที่มา |
|---|---|
| แหล่งที่มา | subagent หรือ cron |
| ID เซสชัน | คีย์/ID เซสชันลูก |
| ประเภท | ประเภทประกาศ + ป้ายกำกับงาน |
| สถานะ | ได้จากผลลัพธ์รันไทม์ (success, error, timeout หรือ unknown) — ไม่ได้ อนุมานจากข้อความโมเดล |
| เนื้อหาผลลัพธ์ | ข้อความผู้ช่วยล่าสุดที่มองเห็นได้ มิฉะนั้นเป็นข้อความ tool/toolResult ล่าสุดที่ผ่านการทำให้ปลอดภัยแล้ว |
| การติดตามผล | คำแนะนำที่อธิบายว่าเมื่อใดควรตอบกลับหรือคงความเงียบ |
งานที่ล้มเหลวในสถานะปลายทางจะรายงานสถานะล้มเหลวโดยไม่เล่นซ้ำข้อความตอบกลับ ที่จับไว้ เมื่อ timeout หากลูกผ่านไปได้เพียงการเรียกเครื่องมือ ประกาศ สามารถยุบประวัตินั้นเป็นสรุปความคืบหน้าบางส่วนแบบสั้น แทนการเล่นเอาต์พุตเครื่องมือดิบซ้ำ
บรรทัดสถิติ
เพย์โหลดประกาศมีบรรทัดสถิติที่ท้ายสุด (แม้ถูกห่อบรรทัด):
- รันไทม์ (เช่น
runtime 5m12s) - การใช้โทเคน (อินพุต/เอาต์พุต/ทั้งหมด)
- ค่าใช้จ่ายประมาณการเมื่อกำหนดราคาของโมเดลไว้ (
models.providers.*.models[].cost) sessionKey,sessionIdและเส้นทางทรานสคริปต์ เพื่อให้เอเจนต์หลักดึงประวัติผ่านsessions_historyหรือตรวจสอบไฟล์บนดิสก์ได้
เมทาดาทาภายในมีไว้สำหรับการประสานงานเท่านั้น การตอบกลับที่แสดงต่อผู้ใช้ ควรเขียนใหม่ด้วยเสียงผู้ช่วยตามปกติ
เหตุใดจึงควรใช้ sessions_history
sessions_history เป็นเส้นทางการประสานงานที่ปลอดภัยกว่า:
- การเรียกคืนของผู้ช่วยถูกทำให้เป็นมาตรฐานก่อน: ลบแท็กการคิด; ลบโครง
<relevant-memories>/<relevant_memories>; ลบบล็อกเพย์โหลด XML การเรียกเครื่องมือแบบข้อความธรรมดา (<tool_call>,<function_call>,<tool_calls>,<function_calls>) รวมถึงเพย์โหลดที่ถูกตัดทอนและไม่เคยปิดอย่างเรียบร้อย; ลบโครง tool-call/result ที่ถูกลดระดับและมาร์กเกอร์บริบทประวัติ; ลบโทเคนควบคุมโมเดลที่รั่ว (<|assistant|>, ASCII<|...|>อื่น, แบบเต็มความกว้าง<|...|>); ลบ XML การเรียกเครื่องมือ MiniMax ที่มีรูปแบบผิด - ข้อความที่ดูเหมือนข้อมูลประจำตัว/โทเคนจะถูกปกปิด
- บล็อกยาวสามารถถูกตัดทอนได้
- ประวัติขนาดใหญ่มากสามารถทิ้งแถวเก่ากว่า หรือแทนที่แถวที่ใหญ่เกินด้วย
[sessions_history omitted: message too large] - การตรวจสอบทรานสคริปต์ดิบบนดิสก์เป็น fallback เมื่อคุณต้องการทรานสคริปต์เต็มแบบตรงทุกไบต์
นโยบายเครื่องมือ
เอเจนต์ย่อยใช้โปรไฟล์และไปป์ไลน์นโยบายเครื่องมือเดียวกับพาเรนต์หรือ เอเจนต์เป้าหมายก่อน หลังจากนั้น OpenClaw จะใช้เลเยอร์ข้อจำกัด เอเจนต์ย่อย
เมื่อไม่มี tools.profile ที่จำกัด เอเจนต์ย่อยจะได้รับ เครื่องมือทั้งหมด ยกเว้น
เครื่องมือเซสชัน และเครื่องมือระบบ:
sessions_listsessions_historysessions_sendsessions_spawn
sessions_history ยังคงเป็นมุมมองการเรียกคืนที่มีขอบเขตและผ่านการทำให้ปลอดภัยที่นี่ด้วย —
ไม่ใช่การดัมป์ทรานสคริปต์ดิบ
เมื่อ maxSpawnDepth >= 2 เอเจนต์ย่อยตัวประสานงานระดับความลึก 1 จะได้รับ
sessions_spawn, subagents, sessions_list และ
sessions_history เพิ่มเติม เพื่อให้จัดการลูกของตัวเองได้
แทนที่ผ่านการกำหนดค่า
{
agents: {
defaults: {
subagents: {
maxConcurrent: 1,
},
},
},
tools: {
subagents: {
tools: {
// deny wins
deny: ["gateway", "cron"],
// if allow is set, it becomes allow-only (deny still wins)
// allow: ["read", "exec", "process"]
},
},
},
}
tools.subagents.tools.allow เป็นตัวกรอง allow-only ขั้นสุดท้าย สามารถจำกัด
ชุดเครื่องมือที่ resolve แล้วให้แคบลงได้ แต่ไม่สามารถ เพิ่มกลับ เครื่องมือที่ถูกนำออก
โดย tools.profile ได้ ตัวอย่างเช่น tools.profile: "coding" รวม
web_search/web_fetch แต่ไม่รวมเครื่องมือ browser หากต้องการให้
sub-agent ที่ใช้ profile แบบ coding ใช้ระบบอัตโนมัติของเบราว์เซอร์ได้ ให้เพิ่ม browser ใน
ขั้น profile:
{
tools: {
profile: "coding",
alsoAllow: ["browser"],
},
}
ใช้ agents.list[].tools.alsoAllow: ["browser"] แบบรายเอเจนต์เมื่อมีเพียง
เอเจนต์เดียวที่ควรได้รับระบบอัตโนมัติของเบราว์เซอร์
ภาวะพร้อมกัน
Sub-agent ใช้ lane คิวในโปรเซสเฉพาะ:
- ชื่อ lane:
subagent - ภาวะพร้อมกัน:
agents.defaults.subagents.maxConcurrent(ค่าเริ่มต้น8)
สถานะมีชีวิตและการกู้คืน
OpenClaw ไม่ถือว่าการไม่มี endedAt เป็นหลักฐานถาวรว่า
sub-agent ยังมีชีวิตอยู่ การรันที่ยังไม่จบซึ่งเก่ากว่าหน้าต่าง stale-run
จะหยุดนับเป็น active/pending ใน /subagents list, สรุปสถานะ,
gating การเสร็จสมบูรณ์ของ descendant และการตรวจสอบภาวะพร้อมกันต่อ session
หลังจาก Gateway รีสตาร์ต การรันที่ restore แล้วแต่ stale และยังไม่จบจะถูกตัดทิ้ง เว้นแต่
session ลูกของการรันนั้นจะถูกทำเครื่องหมาย abortedLastRun: true session ลูกที่
ถูกยกเลิกจากการรีสตาร์ตเหล่านั้นยังสามารถกู้คืนได้ผ่านโฟลว์กู้คืน orphan ของ sub-agent
ซึ่งจะส่งข้อความ resume สังเคราะห์ก่อน
ล้างเครื่องหมาย aborted
การกู้คืนอัตโนมัติหลังรีสตาร์ตถูกจำกัดต่อ session ลูก หาก
sub-agent ลูกตัวเดิมถูกยอมรับให้กู้คืน orphan ซ้ำ ๆ ภายใน
หน้าต่าง rapid re-wedge OpenClaw จะบันทึก recovery tombstone ใน
session นั้นและหยุด auto-resume ให้ในการรีสตาร์ตภายหลัง รัน
openclaw tasks maintenance --apply เพื่อ reconcile task record หรือ
openclaw doctor --fix เพื่อล้าง flag การกู้คืน aborted ที่ stale บน
session ที่ถูก tombstone
การหยุด
- การส่ง
/stopในแชต requester จะยกเลิก session ของ requester และหยุดการรัน sub-agent ที่ active ใด ๆ ที่ spawn จาก session นั้น โดย cascade ไปยังลูกซ้อน /subagents kill <id>หยุด sub-agent เฉพาะตัวและ cascade ไปยังลูกของมัน
ข้อจำกัด
- การ announce ของ sub-agent เป็นแบบ best-effort หาก Gateway รีสตาร์ต งาน "announce back" ที่ pending จะสูญหาย
- Sub-agent ยังคงใช้ทรัพยากรของโปรเซส Gateway เดียวกัน ให้ถือว่า
maxConcurrentเป็นวาล์วนิรภัย sessions_spawnเป็น non-blocking เสมอ: จะคืน{ status: "accepted", runId, childSessionKey }ทันที- context ของ sub-agent inject เฉพาะ
AGENTS.md+TOOLS.md(ไม่มีSOUL.md,IDENTITY.md,USER.md,HEARTBEAT.mdหรือBOOTSTRAP.md) - ความลึกการซ้อนสูงสุดคือ 5 (
maxSpawnDepthrange: 1–5) แนะนำให้ใช้ความลึก 2 สำหรับกรณีใช้งานส่วนใหญ่ maxChildrenPerAgentจำกัดจำนวนลูกที่ active ต่อ session (ค่าเริ่มต้น5, range1–20)