---
read_when:
    - คุณต้องการเปิดใช้งานโหมดโค้ดของ OpenClaw สำหรับการเรียกใช้เอเจนต์
    - คุณต้องอธิบายว่าเหตุใด Code Mode จึงแตกต่างจาก Codex Code Mode
    - คุณกำลังรีวิวสัญญาเครื่องมือแบบกระชับ แซนด์บ็อกซ์ QuickJS-WASI การแปลง TypeScript หรือบริดจ์แค็ตตาล็อกเครื่องมือที่ซ่อนอยู่
    - คุณกำลังเพิ่มหรือรีวิวการผสานรวมรีจิสทรีเนมสเปซโหมดโค้ดภายใน
sidebarTitle: Code Mode
summary: ใช้ Code Mode ของ OpenClaw เพื่อค้นหา เรียกใช้ และผสานแค็ตตาล็อกเครื่องมือขนาดใหญ่ในเวิร์กโฟลว์ JavaScript หรือ TypeScript ที่กระชับ
title: โหมดโค้ด
x-i18n:
    generated_at: "2026-07-19T18:10:49Z"
    model: gpt-5.6
    postprocess_version: locale-links-v1
    prompt_version: 32
    provider: openai
    source_hash: a21df3bcfb11668da6dde1f7c69adcc284a28dc491c95f95097ce7f41e5c45bf
    source_path: tools/code-mode.md
    workflow: 16
---

โหมดโค้ดเป็นฟีเจอร์รันไทม์เอเจนต์ OpenClaw แบบทดลองที่ต้องเลือกเปิดใช้ เมื่อ
เปิดใช้แล้ว โมเดลจะไม่เห็นสคีมาของเครื่องมือที่เปิดใช้ทั้งหมดอีกต่อไป แต่จะเห็น
`exec`, `wait` และเครื่องมือแบบ direct-only ใดๆ ที่ผลลัพธ์แบบมีโครงสร้างไม่สามารถส่งผ่าน
บริดจ์ guest ที่รองรับเฉพาะ JSON ได้ โมเดลจะเขียนโปรแกรม JavaScript หรือ TypeScript
ขนาดเล็กเพื่อค้นหา ดูคำอธิบาย และเรียกใช้แค็ตตาล็อกเครื่องมือที่ซ่อนอยู่

หน้านี้อธิบายโหมดโค้ดของ OpenClaw ไม่ใช่ Codex Code Mode ฟีเจอร์ทั้งสอง
ใช้ชื่อเดียวกันและชื่อเครื่องมือควบคุมเดียวกัน (`exec`, `wait`) แต่เป็น
การใช้งานที่แยกจากกัน:

- Codex Code Mode ทำงานภายในระบบควบคุมการเขียนโค้ดของ Codex เครื่องมือ `exec` ของมันเป็น
  เครื่องมือไวยากรณ์แบบอิสระ: โมเดลเขียนซอร์ส JavaScript ดิบ (อาจ
  นำหน้าด้วยบรรทัด pragma `// @exec: {...}` สำหรับตัวเลือกการดำเนินการ) ซึ่งจะถูกดำเนินการ
  ในรันไทม์ V8 Code Mode ภายในโปรเซสของ Codex
- โหมดโค้ดของ OpenClaw ทำงานในรันไทม์เอเจนต์ OpenClaw ทั่วไป และจะ
  ปิดอยู่เว้นแต่จะกำหนดค่า `tools.codeMode.enabled: true` เครื่องมือ `exec`
  รับเพย์โหลด JSON `{ code, language }` ซึ่งดำเนินการในเวิร์กเกอร์
  QuickJS-WASI

ทั้งสองเป็นพื้นผิวการดำเนินการ JavaScript ไม่ใช่พื้นผิวคำสั่งเชลล์ ให้ถือว่าเป็น
ฟีเจอร์อิสระที่มีการใช้งานแตกต่างกัน ซึ่งบังเอิญเปิดเผยเครื่องมือ
`exec`/`wait` ที่มีชื่อเหมือนกัน

## การทำงาน

- รายการเครื่องมือที่โมเดลมองเห็นจะกลายเป็น `exec`, `wait` รวมถึงเครื่องมือแบบ direct-only ใดๆ
  เช่น `computer` หรือตัวโหลด `image` สำหรับวิชันแบบเนทีฟ ซึ่งผลลัพธ์รูปภาพ
  ไม่สามารถส่งผ่านบริดจ์ guest ได้
- `exec` ประเมิน JavaScript หรือ TypeScript ที่โมเดลสร้างขึ้นในเธรดเวิร์กเกอร์
  QuickJS-WASI ที่แยกออกจากกัน
- เครื่องมือที่เปิดใช้และมีสิทธิ์อยู่ในแค็ตตาล็อกทุกเครื่องมือ (แกนหลัก OpenClaw, Plugin, MCP, ไคลเอนต์) จะถูกซ่อนจากการเป็น
  เครื่องมือเดี่ยวที่โมเดลมองเห็น และเปิดเผยภายในโปรแกรม guest ผ่าน `ALL_TOOLS`
  และ `tools`
- คำอธิบาย `exec` มีดัชนีด่วนแบบจำกัดของรหัสแค็ตตาล็อก OpenClaw/Plugin
  ที่ตรงกัน คำใบ้อินพุตแบบย่อ และคำใบ้เอาต์พุตที่ประกาศแบบย่อเมื่อ
  เครื่องมือที่เชื่อถือได้มีสคีมาเอาต์พุต โดยจะละคำอธิบาย สคีมาแบบเต็ม
  รายการ MCP และรายการที่เกินขีดจำกัดไว้ การค้นหาแค็ตตาล็อกฝั่ง guest ยังคงเป็นทางเลือกสำรอง
- โค้ด guest ค้นหาแค็ตตาล็อกที่ซ่อนอยู่ ดูคำอธิบายสคีมาของเครื่องมือ และเรียกใช้
  เครื่องมือผ่านเส้นทางการดำเนินการเดียวกับที่ใช้ในการทำงานปกติของเอเจนต์ (นโยบาย
  การอนุมัติ ฮุก และเทเลเมทรียังคงมีผลทั้งหมด)
- เครื่องมือ MCP จะถูกจัดกลุ่มภายใต้เนมสเปซ `MCP`; ในโหมดโค้ด วิธีนี้เป็น
  วิธีเดียวที่รองรับสำหรับเรียกใช้เครื่องมือเหล่านั้น
- `wait` ดำเนินการรันโหมดโค้ดที่ระงับไว้ต่อ เมื่อการเรียกเครื่องมือแบบซ้อนยัง
  รอดำเนินการอยู่

โหมดโค้ดเปลี่ยนเฉพาะพื้นผิวการประสานงานที่โมเดลมองเห็นเท่านั้น โดยไม่
แทนที่เครื่องมือ เครื่องมือของ Plugin เครื่องมือ MCP การยืนยันตัวตน นโยบายการอนุมัติ พฤติกรรมของช่องทาง
หรือการเลือกโมเดล

## เหตุผลที่ควรใช้

- พื้นผิวพรอมป์ที่เล็กลง: ผู้ให้บริการได้รับเครื่องมือควบคุมสองรายการ ดัชนีเครื่องมือเนทีฟ
  แบบจำกัด และเฉพาะเครื่องมือโดยตรงไม่กี่รายการที่จำเป็น แทนสคีมาเครื่องมือแบบเต็ม
  หลายสิบหรือหลายร้อยรายการ
- การประสานงานที่ดีขึ้น: โมเดลสามารถใช้ลูป การรวม การแปลงขนาดเล็ก
  ตรรกะแบบมีเงื่อนไข และการเรียกเครื่องมือแบบซ้อนพร้อมกันภายในเซลล์โค้ดเดียว
- ลดจำนวนรอบการรับส่งกับโมเดล: สัญญาเอาต์พุตที่ประกาศไว้ช่วยให้โมเดลเรียกและ
  แปลงผลลัพธ์ของเครื่องมือใน `exec` เดียวได้ ส่วนเอาต์พุตที่ไม่รู้จักจะยังคงส่งค่าดิบก่อน
- ไม่ขึ้นกับผู้ให้บริการ: ใช้งานได้กับเครื่องมือ OpenClaw, Plugin, MCP และไคลเอนต์ โดยไม่
  พึ่งพาการดำเนินการโค้ดแบบเนทีฟของผู้ให้บริการ
- ล้มเหลวแบบปิด: หากเปิดใช้โหมดโค้ดแต่รันไทม์ QuickJS-WASI
  ไม่พร้อมใช้งาน การรันจะล้มเหลวแทนที่จะถอยกลับไปเปิดเผยเครื่องมือโดยตรง
  ในวงกว้างอย่างเงียบๆ

มีประโยชน์สูงสุดสำหรับเอเจนต์ที่เปิดใช้แค็ตตาล็อกเครื่องมือขนาดใหญ่ หรือเวิร์กโฟลว์ที่
โมเดลต้องค้นหา รวม และเรียกใช้เครื่องมือหลายรายการก่อนตอบ

คงการเปิดเผยเครื่องมือโดยตรงไว้สำหรับแค็ตตาล็อกขนาดเล็กหรือโมเดลที่ไม่สามารถ
เขียนโปรแกรมสั้นๆ ได้อย่างเชื่อถือได้ ใช้ [การค้นหาเครื่องมือ](/th/tools/tool-search) เมื่อต้องการ
แค็ตตาล็อกแบบกะทัดรัด แต่ต้องการตัวควบคุมค้นหา/ดูคำอธิบาย/เรียกใช้แบบมีโครงสร้าง แทน
guest QuickJS-WASI

## เริ่มต้นใช้งานอย่างรวดเร็ว

### เปิดใช้โหมดโค้ด

```json5
{
  tools: {
    codeMode: {
      enabled: true,
    },
  },
}
```

รูปแบบย่อ:

```json5
{
  tools: {
    codeMode: true,
  },
}
```

โหมดโค้ดจะยังคงปิดเมื่อไม่ระบุ `tools.codeMode`, เป็น `false` หรือเป็นออบเจ็กต์
ที่ไม่มี `enabled: true`

หากใช้เอเจนต์แบบแซนด์บ็อกซ์ร่วมกับเซิร์ฟเวอร์ MCP ที่กำหนดค่าไว้ ให้อนุญาต
Plugin MCP ที่รวมมาให้ในนโยบายเครื่องมือของแซนด์บ็อกซ์ด้วย เช่น
`tools.sandbox.tools.alsoAllow: ["bundle-mcp"]` ดู
[การกำหนดค่า - เครื่องมือและผู้ให้บริการแบบกำหนดเอง](/th/gateway/config-tools#mcp-and-plugin-tools-inside-sandbox-tool-policy)

กำหนดขีดจำกัดอย่างชัดเจนเพื่อให้ข้อจำกัดรัดกุมยิ่งขึ้น:

```json5
{
  tools: {
    codeMode: {
      enabled: true,
      timeoutMs: 10000,
      memoryLimitBytes: 67108864,
      maxOutputBytes: 65536,
      maxSnapshotBytes: 10485760,
      maxPendingToolCalls: 16,
      snapshotTtlSeconds: 900,
      searchDefaultLimit: 8,
      maxSearchLimit: 50,
    },
  },
}
```

### สิ่งที่โมเดลทำ

สำหรับเครื่องมือที่มีเอาต์พุตประกาศไว้ เช่น
`Array<{ id: string; paid: boolean; tons: number }>` โปรแกรม guest โปรแกรมเดียวสามารถ
เลือก เรียกใช้ และแปลงเครื่องมือนั้นได้:

```javascript
const [shipmentTool] = await tools.search("list shipments");
const shipments = await tools.callValue(shipmentTool.id, {});
return shipments.filter((shipment) => !shipment.paid && shipment.tons > 10);
```

เมื่อบรรทัดดัชนีด่วนลงท้ายด้วย `-> ?` จะไม่ทราบรูปร่างเอาต์พุต `exec` ครั้งแรก
ต้องส่งคืน `await tools.callValue(...)` โดยไม่เปลี่ยนแปลง ส่วน `exec` ในภายหลังสามารถ
แปลงค่าที่สังเกตได้ วิธีนี้ต้องใช้รอบโมเดลเพิ่มอีกหนึ่งรอบ แต่ป้องกันไม่ให้
โมเดลคาดเดาชื่อฟิลด์

### ตรวจสอบพื้นผิวที่ใช้งานอยู่

เพื่อยืนยันรูปร่างเพย์โหลดของโมเดลระหว่างการดีบัก ให้รัน Gateway พร้อม
การบันทึกล็อกแบบเจาะจง:

```bash
OPENCLAW_DEBUG_CODE_MODE=1 \
OPENCLAW_DEBUG_MODEL_TRANSPORT=1 \
OPENCLAW_DEBUG_MODEL_PAYLOAD=tools \
openclaw gateway
```

เมื่อโหมดโค้ดทำงาน ชื่อเครื่องมือที่โมเดลมองเห็นในล็อกควรเป็น `exec` และ
`wait` สำหรับเพย์โหลดผู้ให้บริการฉบับเต็มที่ปกปิดข้อมูลแล้ว ให้เพิ่ม
`OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted` สำหรับเซสชันดีบักช่วงสั้นๆ

## ใช้ Swarm สำหรับการกระจายงานไปยังเอเจนต์

[Swarm](/tools/swarm) เพิ่มโกลบอล guest `agents.run()`, `phase()` และ `log()`
สำหรับประสานงานซับเอเจนต์พร้อมกันจากสคริปต์โหมดโค้ด เปิดใช้ทั้ง
`tools.codeMode` และ `tools.swarm` แล้วใช้โฟลว์ควบคุม JavaScript ปกติสำหรับ
การกระจายงาน เกตการตัดสินใจ และการรวบรวมแบบมีโครงสร้าง Swarm เป็นเกตแบบเลือกเปิดใช้
ที่แยกต่างหาก การเปิดใช้โหมดโค้ดเพียงอย่างเดียวจะไม่เปิดเผย API `agents.*`

## ภาพรวมเชิงเทคนิค

ส่วนที่เหลือของหน้านี้กล่าวถึงสัญญารันไทม์และรายละเอียดการใช้งาน
สำหรับผู้ดูแล ผู้เขียน Plugin ที่กำลังดีบักการเปิดเผยเครื่องมือ และผู้ปฏิบัติงาน
ที่กำลังตรวจสอบการนำไปใช้งานที่มีความเสี่ยงสูง

## สถานะรันไทม์

|                     |                                                                                             |
| ------------------- | ------------------------------------------------------------------------------------------- |
| รันไทม์             | [`quickjs-wasi`](https://github.com/vercel-labs/quickjs-wasi)                               |
| สถานะเริ่มต้น       | ปิดใช้งาน                                                                                    |
| ความเสถียร           | พื้นผิว OpenClaw แบบทดลอง (Codex Code Mode เป็นพื้นผิวระบบควบคุม Codex ที่เสถียรและแยกต่างหาก) |
| พื้นผิวเป้าหมาย      | การรันเอเจนต์ OpenClaw ทั่วไป                                                                 |
| แนวทางด้านความปลอดภัย | ถือว่าโค้ดของโมเดลเป็นอันตราย                                                                  |
| คำมั่นต่อผู้ใช้       | การเปิดใช้โหมดโค้ดจะไม่ถอยกลับไปเปิดเผยเครื่องมือโดยตรงในวงกว้างอย่างเงียบๆ                    |

## ขอบเขต

โหมดโค้ดเป็นเจ้าของรูปร่างการประสานงานที่โมเดลมองเห็นสำหรับการรันที่เตรียมไว้ โดย
ไม่ได้เป็นเจ้าของการเลือกโมเดล พฤติกรรมของช่องทาง การยืนยันตัวตน นโยบายเครื่องมือ หรือการใช้งาน
เครื่องมือ

อยู่ในขอบเขต: คำนิยามเครื่องมือควบคุม/โดยตรงที่โมเดลมองเห็น การสร้างแค็ตตาล็อกเครื่องมือ
ที่ซ่อนอยู่ การดำเนินการ guest ของ JavaScript/TypeScript รันไทม์เวิร์กเกอร์
QuickJS-WASI คอลแบ็กโฮสต์สำหรับค้นหา/ดูคำอธิบาย/เรียกใช้ สถานะที่ดำเนินการต่อได้สำหรับ
โปรแกรม guest ที่ระงับ ขีดจำกัดเอาต์พุต/เวลาหมด/หน่วยความจำ/การเรียกที่รอดำเนินการ/สแนปช็อต
และการฉายข้อมูลเทเลเมทรี/วิถีการทำงานสำหรับการเรียกเครื่องมือแบบซ้อน

อยู่นอกขอบเขต: การดำเนินการโค้ดระยะไกลแบบเนทีฟของผู้ให้บริการ ความหมายของการดำเนินการ
เชลล์ การเปลี่ยนการอนุญาตเครื่องมือที่มีอยู่ สคริปต์ที่ผู้ใช้เขียนและจัดเก็บถาวร
การเข้าถึงตัวจัดการแพ็กเกจ/ไฟล์/เครือข่าย/โมดูลในโค้ด guest และการนำส่วนภายในของ
Codex Code Mode มาใช้โดยตรง

เครื่องมือที่ผู้ให้บริการเป็นเจ้าของ เช่น แซนด์บ็อกซ์ Python ระยะไกล เป็นเครื่องมือที่แยกต่างหาก ดู
[การดำเนินการโค้ด](/th/tools/code-execution)

## คำศัพท์

- **โหมดโค้ด**: โหมดรันไทม์ OpenClaw ที่ซ่อนเครื่องมือโมเดลซึ่งเข้ากันได้กับแค็ตตาล็อก
  และเปิดเผย `exec`, `wait` รวมถึงเครื่องมือแบบ direct-only ที่จำเป็น
- **รันไทม์ guest**: VM JavaScript ของ QuickJS-WASI ที่ประเมินโค้ดของโมเดล
- **บริดจ์โฮสต์**: พื้นผิวคอลแบ็กที่แคบและเข้ากันได้กับ JSON จากโค้ด guest
  กลับเข้าสู่ OpenClaw
- **แค็ตตาล็อก**: รายการเครื่องมือที่มีผลในขอบเขตการรัน หลังการแก้ไข
  นโยบายเครื่องมือ Plugin, MCP และเครื่องมือไคลเอนต์ตามปกติ
- **การเรียกเครื่องมือแบบซ้อน**: การเรียกเครื่องมือจากโค้ด guest ผ่านบริดจ์
  โฮสต์
- **สแนปช็อต**: สถานะ VM QuickJS-WASI ที่ซีเรียลไลซ์และบันทึกไว้ เพื่อให้ `wait` สามารถดำเนินการ
  รันโหมดโค้ดที่ระงับไว้ต่อได้

## การกำหนดค่า

`tools.codeMode.enabled` เป็นเกตการเปิดใช้งาน การตั้งค่าฟิลด์อื่นจะไม่
เปิดใช้ฟีเจอร์นี้ด้วยตัวเอง

| ฟิลด์                 | ค่าเริ่มต้น                        | ข้อจำกัด                                           |
| --------------------- | ------------------------------ | ----------------------------------------------- |
| `enabled`             | `false`                        | บูลีน; เฉพาะ `true` เท่านั้นที่เปิดใช้โหมดโค้ด          |
| `runtime`             | `"quickjs-wasi"`               | ค่าที่รองรับเพียงค่าเดียว                            |
| `mode`                | `"only"`                       | เปิดเผยเครื่องมือควบคุม/โดยตรง และจัดรายการที่เหลือไว้ในแค็ตตาล็อก |
| `languages`           | `["javascript", "typescript"]` | เซตย่อยใดๆ ของทั้งสองรายการ                           |
| `timeoutMs`           | `10000`                        | `100`-`60000`                                   |
| `memoryLimitBytes`    | `67108864`                     | `1048576`-`1073741824`                          |
| `maxOutputBytes`      | `65536`                        | `1024`-`10485760`                               |
| `maxSnapshotBytes`    | `10485760`                     | `1024`-`268435456`                              |
| `maxPendingToolCalls` | `16`                           | `1`-`128`                                       |
| `snapshotTtlSeconds`  | `900`                          | `1`-`86400`                                     |
| `searchDefaultLimit`  | `8`                            | จำกัดไว้ที่ `maxSearchLimit`                     |
| `maxSearchLimit`      | `50`                           | `1`-`50`                                        |

หากเปิดใช้โหมดโค้ดแต่ไม่สามารถโหลด QuickJS-WASI ได้ OpenClaw จะล้มเหลวแบบปิด
สำหรับการรันนั้น โดยจะไม่เปิดเผยเครื่องมือปกติเป็นทางเลือกสำรองอย่างเงียบๆ

## การเปิดใช้งาน

โหมดโค้ดจะได้รับการประเมินหลังจากทราบนโยบายเครื่องมือที่มีผลแล้ว และก่อน
ประกอบคำขอสุดท้ายสำหรับโมเดล:

1. ระบุเอเจนต์ โมเดล ผู้ให้บริการ แซนด์บ็อกซ์ ช่องทาง ผู้ส่ง และนโยบาย
   การรัน
2. สร้างรายการเครื่องมือ OpenClaw ที่มีผล โดยเพิ่มเครื่องมือ Plugin, MCP และ
   ไคลเอนต์ที่เข้าเกณฑ์
3. ใช้นโยบายอนุญาต/ปฏิเสธ
4. หาก `tools.codeMode.enabled` เป็น false ให้เปิดเผยเครื่องมือตามปกติต่อไป
5. หากเปิดใช้งานและมีเครื่องมือที่ทำงานสำหรับการรัน ให้คงเครื่องมือ direct-only
   ที่จำเป็นไว้ และลงทะเบียนเครื่องมือที่มีผลซึ่งเข้าเกณฑ์แค็ตตาล็อกทุกรายการในแค็ตตาล็อก
   โหมดโค้ด
6. นำเครื่องมือที่ลงแค็ตตาล็อกแล้วออกจากรายการที่โมเดลมองเห็น และเพิ่ม `exec` กับ
   `wait` ควบคู่กับเครื่องมือ direct-only ที่คงไว้

การรันที่ตั้งใจไม่ให้มีเครื่องมือ (การเรียกโมเดลดิบ, `disableTools: true`
หรือรายการ `tools.allow` ที่ว่าง) จะไม่เปิดใช้งานพื้นผิวโหมดโค้ด แม้
จะกำหนดค่า `tools.codeMode.enabled: true` ไว้ โหมดโค้ดและการค้นหาเครื่องมือของ OpenClaw
ใช้ร่วมกันไม่ได้ในการรันเดียว หากโหมดโค้ดเปิดใช้งาน Compaction ของการค้นหาเครื่องมือ
จะไม่ทำงาน

แค็ตตาล็อกโหมดโค้ดมีขอบเขตเฉพาะการรัน และต้องไม่ทำให้เครื่องมือจาก
เอเจนต์ เซสชัน ผู้ส่ง หรือการรันอื่นรั่วไหลเข้ามา

## เครื่องมือที่โมเดลมองเห็น

เมื่อโหมดโค้ดทำงาน โมเดลจะเห็น `exec`, `wait` และเครื่องมือ
direct-only ที่จำเป็น เครื่องมืออื่นทุกตัวที่เปิดใช้งานจะถูกซ่อนจากรายการเครื่องมือ
ที่แสดงต่อโมเดล และลงทะเบียนในแค็ตตาล็อกโหมดโค้ด

ใช้ `exec` สำหรับการประสานงานเครื่องมือ การรวมข้อมูล ลูป การเรียกซ้อนแบบขนาน
และการแปลงข้อมูลแบบมีโครงสร้าง ใช้ `wait` เฉพาะเมื่อ `exec` ส่งคืนผลลัพธ์
`waiting` ที่ดำเนินการต่อได้

## `exec`

`exec` เริ่มเซลล์โหมดโค้ดและส่งคืนผลลัพธ์หนึ่งรายการ โค้ดอินพุตสร้างโดยโมเดล
และต้องถือว่าเป็นอันตราย

อินพุต:

```typescript
type CodeModeExecInput = {
  code?: string;
  command?: string;
  language?: "javascript" | "typescript";
};
```

กฎ:

- ต้องมีค่าอย่างใดอย่างหนึ่งระหว่าง `code` หรือ `command`
- `code` คือฟิลด์ที่แสดงต่อโมเดลตามเอกสาร
- ยอมรับ `command` เป็นนามแฝงที่เข้ากันได้กับ exec สำหรับนโยบาย hook และ
  การเขียนใหม่ที่เชื่อถือได้ (เครื่องมือ shell exec ปกติของ OpenClaw ก็ใช้ฟิลด์ `command`
  เช่นกัน) เมื่อมีทั้งสองค่า ค่าต้องตรงกัน
- `language` มีค่าเริ่มต้นเป็น `"javascript"`; สคีมาเปิดเผยเป็น string enum
  แบบแบน (`"javascript" | "typescript"`) ไม่ใช่ยูเนียน `oneOf`/`anyOf`
  เนื่องจากผู้ให้บริการบางรายปฏิเสธรูปแบบเหล่านั้น
- หาก `language` เป็น `"typescript"` OpenClaw จะทรานสไพล์ก่อนประเมินผล
- `exec` ปฏิเสธ `import`, `require`, dynamic import และรูปแบบ
  module-loader
- `exec` จะไม่เปิดเผยการติดตั้งใช้งาน shell `exec` ปกติแบบเรียกซ้ำ
- เหตุการณ์ hook `exec` ของโหมดโค้ดชั้นนอกมี `toolKind: "code_mode_exec"` และ
  `toolInputKind: "javascript" | "typescript"` (เมื่อทราบ) เพื่อให้นโยบายสามารถ
  แยกเซลล์โหมดโค้ดออกจากการเรียก `exec` แบบ shell ซึ่งใช้
  ชื่อเครื่องมือเดียวกัน

ผลลัพธ์:

```typescript
type CodeModeResult = CodeModeCompletedResult | CodeModeWaitingResult | CodeModeFailedResult;

type CodeModeCompletedResult = {
  status: "completed";
  value: unknown;
  output?: CodeModeOutput[];
  telemetry: CodeModeTelemetry;
};

type CodeModeWaitingResult = {
  status: "waiting";
  runId: string;
  reason: "pending_tools" | "yield";
  pendingToolCalls?: CodeModePendingToolCall[];
  output?: CodeModeOutput[];
  telemetry: CodeModeTelemetry;
};

type CodeModeFailedResult = {
  status: "failed";
  error: string;
  code?: CodeModeErrorCode;
  output?: CodeModeOutput[];
  telemetry: CodeModeTelemetry;
};
```

`exec` ส่งคืน `waiting` เมื่อเกสต์พักการทำงานพร้อมสถานะที่ดำเนินการต่อได้ ซึ่งยัง
ต้องการการดำเนินการต่อที่โมเดลมองเห็น เช่น `yield_control(...)` แบบชัดแจ้ง หรือ
การเรียกเครื่องมือบริดจ์ที่ยังไม่เสร็จสิ้นภายในกำหนดเวลาของ exec ผลลัพธ์
จะมี `runId` สำหรับ `wait` การเรียกเครื่องมือบริดจ์ ได้แก่ `tools.search`/`describe`/
`call` และการเรียกเนมสเปซ รวมถึงการเรียกเนมสเปซ MCP จะถูกระบายอัตโนมัติ
ภายในสายเรียก `exec`/`wait` เดียวกัน ตราบใดที่ดำเนินการเสร็จภายในกำหนดเวลา ดังนั้น
บล็อกโค้ดขนาดกะทัดรัดที่รอเครื่องมือหลายตัวจึงทำงานจนเสร็จในการผลัดเดียวของโมเดล
แทนที่จะบังคับให้เรียกเครื่องมือโมเดลหนึ่งครั้งต่อ await การรันที่ปลอดภัยต่อการรีสตาร์ตจะไม่
ระบายอัตโนมัติ งานที่ค้างอยู่ยังคงผ่านการตรวจสอบที่ปลอดภัยต่อการเล่นซ้ำ

`exec` ส่งคืน `completed` เฉพาะเมื่อ VM ของเกสต์ไม่มีงานค้างอยู่และ
ค่าสุดท้ายเข้ากันได้กับ JSON หลังจากอะแดปเตอร์เอาต์พุตของ OpenClaw ทำงานแล้ว

## `wait`

`wait` ดำเนินการต่อ VM โหมดโค้ดที่พักการทำงานไว้

อินพุต:

```typescript
type CodeModeWaitInput = {
  runId: string;
};
```

เอาต์พุตเป็นยูเนียน `CodeModeResult` เดียวกับที่ `exec` ส่งคืน

`wait` มีอยู่เนื่องจากเครื่องมือ OpenClaw ที่ซ้อนกันอาจทำงานช้า โต้ตอบได้
ถูกควบคุมด้วยการอนุมัติ หรือสตรีมการอัปเดตบางส่วน โมเดลไม่ควรต้องเปิด
การเรียก `exec` ที่ยาวไว้ขณะที่โฮสต์รอการทำงานภายนอก

QuickJS-WASI snapshot/restore คือกลไกการดำเนินการต่อ:

1. `exec` ประเมินโค้ดจนเสร็จสิ้น ล้มเหลว หรือพักการทำงาน
2. เมื่อพักการทำงาน OpenClaw จะสร้างสแนปช็อตของ QuickJS VM และบันทึกงาน
   ของโฮสต์ที่ค้างอยู่
3. เมื่องานที่ค้างอยู่เสร็จสิ้น `wait` จะกู้คืนสแนปช็อต VM และ
   ลงทะเบียน callback ของโฮสต์อีกครั้งด้วยชื่อที่คงที่
4. OpenClaw ส่งผลลัพธ์ของเครื่องมือที่ซ้อนกันเข้าสู่ VM ที่กู้คืนแล้ว และระบาย
   งานที่ค้างอยู่ของ QuickJS
5. `wait` ส่งคืน `completed`, `failed` หรือผลลัพธ์ `waiting` อื่น

สแนปช็อตเป็นสถานะรันไทม์ ไม่ใช่อาร์ติแฟกต์ของผู้ใช้ โดยอยู่เฉพาะใน
แมปภายในโปรเซส (ไม่มีการเขียนฐานข้อมูลหรือดิสก์) มีการจำกัดขนาด หมดอายุได้ และมี
ขอบเขตเฉพาะการรันและเซสชันที่สร้างสแนปช็อตนั้น

`wait` ล้มเหลว (ในรูปผลลัพธ์ `failed`) เมื่อ:

- ไม่รู้จัก `runId` หรือสแนปช็อตหมดอายุแล้ว
- ผู้เรียกไม่ได้อยู่ในขอบเขตการรัน/เซสชันเดียวกับการรันที่พักไว้
- มี `wait` กำลังทำงานอยู่แล้วสำหรับ `runId` นั้น
- การกู้คืน QuickJS-WASI ล้มเหลว
- การดำเนินการต่อจะเกิน `maxOutputBytes` หรือ `maxSnapshotBytes`

## API รันไทม์ของเกสต์

```typescript
declare const ALL_TOOLS: ToolCatalogEntry[];
declare const tools: ToolCatalog;
declare const MCP: Record<string, unknown>;
declare const namespaces: Record<string, unknown>;

declare function text(value: unknown): void;
declare function json(value: unknown): void;
declare function yield_control(reason?: string): Promise<void>;
```

`ALL_TOOLS` คือเมทาดาทาขนาดกะทัดรัดสำหรับแค็ตตาล็อกที่มีขอบเขตเฉพาะการรัน โดยค่าเริ่มต้น
จะไม่มีสคีมาเต็ม คำอธิบาย `exec` ที่โมเดลมองเห็นยังรวมถึง
ชุดย่อยแบบจำกัดและกำหนดได้แน่นอนของ id ที่ตรงกันจาก OpenClaw/Plugin คำใบ้อินพุต
แบบกะทัดรัด และคำใบ้เอาต์พุตที่ประกาศและเชื่อถือได้ คำอธิบายจะยังถูกเลื่อนการโหลดไว้ เพื่อไม่ให้
ข้อความแค็ตตาล็อกที่เป็นอันตรายชักนำโมเดล เมื่อดัชนีนั้นไม่มีเครื่องมือรายการหนึ่ง
ให้อ่าน `ALL_TOOLS` หรือเรียก `tools.search(...)` ภายในโปรแกรมเกสต์

ลูกศรในแต่ละบรรทัดของดัชนีด่วนอธิบายค่า `tools.callValue(...)`
`-> Array<{ id: string }>` คือคำใบ้เอาต์พุตที่ประกาศ ส่วน `-> ?` หมายถึงไม่ทราบเอาต์พุต
เอาต์พุตที่ไม่ทราบจะเน้นค่าดิบก่อน: ส่งคืนค่าโดยไม่เปลี่ยนแปลง สังเกตค่านั้น แล้วจึง
กรองหรือแมปใน `exec` ภายหลังแทนการเดาชื่อฟิลด์ หลักการนี้ยัง
ใช้เมื่อการอ่านเอาต์พุตที่ประกาศไว้ส่งต่อไปยังการเรียก `-> ?` ขั้นสุดท้าย: ให้ส่งคืน
ค่าดิบของการเรียกนั้นโดยไม่ห่อด้วยรูปแบบคำตอบที่ร้องขอ

```typescript
type ToolCatalogEntry = {
  id: string;
  name: string;
  label?: string;
  description: string;
  source: "openclaw" | "mcp" | "client";
  sourceName?: string;
  input: string;
  output?: string;
};
```

`input` คือลายเซ็นรูปแบบ TypeScript แบบจำกัดสำหรับกรณีทั่วไป ใช้
`tools.describe(...)` เมื่อยังต้องการสคีมาเต็มที่ตรงกัน รายการ MCP ระยะไกล
และไคลเอนต์ใช้ `input: "unknown"` เพื่อให้สคีมาที่ไม่น่าเชื่อถือยังคง
ถูกเลื่อนการโหลดจนถึง `describe` ส่วน `output`
จะมีเฉพาะคำใบ้แบบกะทัดรัดที่สมบูรณ์ซึ่งได้มาจาก `outputSchema` ของแกนหลัก
OpenClaw หรือ Plugin ที่เชื่อถือได้ การอ้างสคีมาเอาต์พุตจาก MCP และไคลเอนต์จะไม่ถูกยกระดับ
เป็นคำใบ้แค็ตตาล็อกที่เชื่อถือได้นี้

เครื่องมือ Plugin ใช้ `source: "openclaw"` โดยตั้งค่า `sourceName` เป็น id ของ
Plugin เจ้าของ โดยไม่มีค่าแหล่งที่มา `"plugin"` แยกต่างหาก `source: "mcp"`
ใช้เฉพาะกับรายการ MCP ในเมทาดาทา `sourceName`/`mcp` (และถูกกรองออก
จาก `ALL_TOOLS`/`tools.*` โปรดดูด้านล่าง)

สคีมาเต็มจะโหลดเมื่อร้องขอเท่านั้น:

```typescript
type ToolCatalogEntryWithSchema = ToolCatalogEntry & {
  parameters: unknown;
  outputSchema?: unknown;
};
```

ตัวช่วยแค็ตตาล็อก:

```typescript
type ToolCatalog = {
  search(query: string, options?: { limit?: number }): Promise<ToolCatalogEntry[]>;
  describe(id: string): Promise<ToolCatalogEntryWithSchema>;
  callValue(id: string, input?: unknown): Promise<unknown>;
  call(id: string, input?: unknown): Promise<unknown>;
  [safeToolName: string]: unknown;
};
```

ฟังก์ชันเครื่องมือเพื่อความสะดวกจะติดตั้งเฉพาะชื่อที่ปลอดภัยและไม่กำกวม:

```typescript
const files = await tools.search("read local file");
const fileRead = await tools.describe(files[0].id);
const content = await tools.callValue(fileRead.id, { path: "README.md" });

// หากแค็ตตาล็อกที่ซ่อนอยู่มีรายการ `web_search` ที่ไม่กำกวม:
const hits = await tools.web_search({ query: "OpenClaw code mode" });
```

`tools.callValue(...)` ส่งคืนค่า JSON `details` ของเครื่องมือปกติโดยตรง
`tools.call(...)` จะรักษาเอนเวโลป `{ tool, result }` แบบดิบไว้สำหรับผู้เรียก
ที่ต้องการบล็อกเนื้อหาหรือเมทาดาทาผลลัพธ์อื่น

## สัญญาเอาต์พุตที่ประกาศ

เครื่องมือ OpenClaw สามารถประกาศ `outputSchema` สำหรับค่าแบบมีโครงสร้างที่ใส่ไว้ใน
`AgentToolResult.details` ซึ่งมีประโยชน์สำหรับโหมดโค้ดและการค้นหาเครื่องมือ แต่
ไม่ใช่สคีมาการตอบกลับเครื่องมือแบบเนทีฟของผู้ให้บริการ และไม่เปลี่ยนการเปิดเผยเครื่องมือ
โดยตรง

สำหรับเครื่องมือที่สร้างด้วย `defineToolPlugin` ให้ประกาศสคีมาไว้ข้าง
`parameters`:

```typescript
import { Type } from "typebox";
import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin";

const Shipment = Type.Object(
  {
    id: Type.String(),
    paid: Type.Boolean(),
    tons: Type.Number(),
  },
  { additionalProperties: false },
);

export default defineToolPlugin({
  id: "shipping",
  name: "Shipping",
  description: "Shipment tools.",
  tools: (tool) => [
    tool({
      name: "shipping_list",
      description: "List shipments.",
      parameters: Type.Object({}),
      outputSchema: Type.Array(Shipment),
      execute: async () => loadShipments(),
    }),
  ],
});
```

สำหรับ `api.registerTool(...)` หรือเครื่องมือจาก factory ให้ใส่พร็อพเพอร์ตี `outputSchema`
เดียวกันบนออบเจ็กต์ `AnyAgentTool` ที่ส่งคืน

สัญญาในตัวปัจจุบันประกอบด้วย `agents_list`, `apply_patch`,
`conversations_list`, `conversations_send`, `conversations_turn`, `edit`,
`openclaw`, `read`, `screen`,
`sessions_history`, `sessions_list`, `sessions_search`, `sessions_send`,
`session_status`, `spawn_task`, `terminal`, `web_fetch` และ `web_search`
การส่งผ่านโดยตรงอย่างแม่นยำสามารถนำสคีมาของโปรโตคอลเจ้าของกลับมาใช้แทน
การทำสัญญาสำหรับโมเดลเท่านั้นซ้ำได้ ตัวอย่างเช่น เครื่องมือการสนทนาเปิดเผย
สคีมาผลลัพธ์ Gateway เดียวกับที่ใช้โดย `conversations.list`,
`conversations.send` และ `conversations.turn`; `web_fetch` เป็นเจ้าของสคีมา
เฉพาะเครื่องมือซึ่งคำใบ้เปิดเผยเมทาดาทาที่เสถียร ข้อความ สถานะแคช และเมทาดาทา
การล้นแบบซ้อน; `web_search` ประกาศยูเนียนผลลัพธ์/คำตอบ/ข้อผิดพลาด/ข้อมูลดิบ
ที่ผ่านการทำให้เป็นมาตรฐานอย่างแม่นยำเป็นคำใบ้ดัชนีด่วนที่สมบูรณ์ สัญญาระบบไฟล์ส่งคืน
ผลลัพธ์แบบมีโครงสร้างสำหรับข้อความที่อ่าน รูปภาพ การตัดทอน และตัวเลือกไม่พบไฟล์;
สถานะการเปลี่ยนแปลงจากการแก้ไขอย่างชัดเจนพร้อมข้อมูล diff/patch; และข้อมูลสรุปพาธ
ของ apply-patch เมื่อดัชนีด่วนประกาศฟิลด์ เซลล์เดียวสามารถรวมการค้นหาและการส่งมอบ
โดยไม่ต้องใช้รอบตรวจสอบแยกต่างหาก:

```javascript
const listed = await tools.conversations_list({ query: "บอตบิลด์" });
const target = listed.conversations.find((item) => item.label === "บอตบิลด์");
if (!target) throw new Error("ไม่พบการสนทนา");
return await tools.conversations_send({
  conversationRef: target.conversationRef,
  message: "บิลด์เสร็จสิ้นแล้ว",
});
```

การเรียกแบบซ้อนยังคงใช้นโยบายเครื่องมือ ฮุก และการอนุมัติตามปกติ หากสัญญาฉบับเต็ม
มีความแม่นยำแต่ใหญ่เกินไปสำหรับดัชนีด่วนที่มีขอบเขต สัญญานั้นยังคงเข้าถึงได้ผ่าน
`tools.describe(...)` และลูกศรยังคงเป็น `-> ?`

กฎของสัญญาเข้มงวดดังนี้:

- อธิบายค่า `details` ที่เข้ากันได้กับ JSON อย่างแม่นยำ ไม่ใช่บล็อก
  `content` ที่เรนเดอร์แล้วหรือเอนเวโลปของผู้ให้บริการ
- รวมตัวแปรผลลัพธ์สำเร็จหรือข้อผิดพลาดทุกแบบที่ไม่โยนข้อยกเว้น ละเว้น `outputSchema` เมื่อ
  เครื่องมือไม่มีผลลัพธ์แบบมีโครงสร้างที่เสถียร
- ปิดเลเยอร์ออบเจ็กต์ด้วย `{ additionalProperties: false }` เพื่อให้ได้
  คำใบ้ดัชนีด่วนที่สมบูรณ์ สคีมาที่เปิด ใหญ่เกินไป หรือไม่สมบูรณ์ในลักษณะอื่น
  ยังคงเข้าถึงได้ผ่าน `tools.describe(...)` แต่ไม่เปิดใช้การใช้ฟิลด์ในรอบเดียว
- OpenClaw คอมไพล์สคีมาก่อนเรียกใช้เครื่องมือ จากนั้นตรวจสอบ
  `details` สุดท้ายหลังจากฮุกเครื่องมือตามปกติและก่อนการเรียกแค็ตตาล็อกส่งคืน
  สคีมาที่ไม่ถูกต้องไม่สามารถเรียกใช้เครื่องมือได้; หากข้อมูลไม่ตรงกัน การทำงานจะล้มเหลว
  โดยไม่พิมพ์ค่า
- คำใบ้แบบกะทัดรัดมีลักษณะกำหนดแน่นอนและมีขอบเขต `tools.describe(...)` เปิดเผย
  สคีมาที่เชื่อถือได้ฉบับเต็มเมื่อคำใบ้แบบกะทัดรัดไม่เพียงพอ
- โค้ด Plugin ที่ติดตั้งเป็นโค้ดภายในที่เชื่อถือได้อยู่แล้ว เมทาดาทาจาก MCP ระยะไกล
  และไคลเอนต์ยังคงไม่น่าเชื่อถือและไม่สามารถเลือกใช้คำใบ้ดัชนีด่วนเหล่านี้ได้

ดูรายละเอียดการสร้าง Plugin ที่ [Plugin เครื่องมือ](/th/plugins/tool-plugins#output-contracts)

รายการแค็ตตาล็อก MCP ไม่สามารถเรียกผ่าน `tools.callValue(...)`,
`tools.call(...)` หรือฟังก์ชันอำนวยความสะดวกในโหมดโค้ดได้; รายการเหล่านี้เปิดเผย
ผ่านเนมสเปซ `MCP` ที่สร้างขึ้นเท่านั้น ไฟล์ประกาศรูปแบบ TypeScript
เข้าถึงได้ผ่านพื้นผิวไฟล์เสมือนแบบอ่านอย่างเดียว `API` เพื่อให้เอเจนต์
ตรวจสอบลายเซ็น MCP ได้โดยไม่เพิ่มสคีมา MCP ลงในพรอมต์:

```typescript
const files = await API.list("mcp");
const githubApi = await API.read("mcp/github.d.ts");

const issue = await MCP.github.createIssue({
  owner: "openclaw",
  repo: "openclaw",
  title: "ตรวจสอบบันทึก Gateway",
});

const snapshot = await MCP.chromeDevtools.takeSnapshot({ output: "markdown" });
const resource = await MCP.docs.resources.read({ uri: "memo://one" });
const prompt = await MCP.docs.prompts.get({
  name: "brief",
  arguments: { topic: "release" },
});
```

`API.read("mcp/<server>.d.ts")` ส่งคืนประกาศแบบกะทัดรัดที่อนุมานจาก
เมทาดาทาเครื่องมือ MCP:

```typescript
type McpToolResult = {
  content?: unknown[];
  structuredContent?: unknown;
  isError?: boolean;
  [key: string]: unknown;
};

declare namespace MCP.github {
  /** ส่งคืนส่วนหัว API รูปแบบ TypeScript นี้ */
  function $api(toolName?: string, options?: { schema?: boolean }): Promise<McpApiHeader>;

  /**
   * สร้าง issue ใน GitHub
   * @param owner เจ้าของรีโพซิทอรี
   * @param repo ชื่อรีโพซิทอรี
   * @param title ชื่อ issue
   */
  function createIssue(input: {
    owner: string;
    repo: string;
    title: string;
    body?: string;
  }): Promise<McpToolResult>;
}
```

ไฟล์ประกาศเป็นไฟล์เสมือน ไม่ได้เขียนไว้ใต้ไดเรกทอรีเวิร์กสเปซหรือสถานะ
สำหรับการเรียก `exec` ในโหมดโค้ดแต่ละครั้ง OpenClaw จะสร้างแค็ตตาล็อก
เครื่องมือตามขอบเขตการรัน เก็บรายการ MCP ที่มองเห็นได้ เรนเดอร์ `mcp/index.d.ts`
พร้อม `mcp/<server>.d.ts` หนึ่งรายการต่อเซิร์ฟเวอร์ที่มองเห็นได้ และแทรกตารางขนาดเล็ก
แบบอ่านอย่างเดียวนี้ลงในเวิร์กเกอร์ QuickJS โค้ดเกสต์มองเห็นเฉพาะออบเจ็กต์
`API`: `API.list(prefix?)` ส่งคืนเมทาดาทาไฟล์ และ `API.read(path)`
ส่งคืนเนื้อหาประกาศที่เลือก พาธที่ไม่รู้จักและเซกเมนต์
`.`/`..` จะถูกปฏิเสธ

วิธีนี้กันสคีมา MCP ขนาดใหญ่ออกจากพรอมต์ของโมเดล: เอเจนต์เรียนรู้ว่า
API เสมือนมีอยู่จากคำอธิบายเครื่องมือ `exec` อ่านเฉพาะไฟล์ประกาศ
ที่จำเป็น จากนั้นเรียก `MCP.<server>.<tool>()` ด้วยอาร์กิวเมนต์ออบเจ็กต์หนึ่งรายการ
`MCP.<server>.$api()` ยังคงใช้เป็นทางเลือกสำรองแบบอินไลน์สำหรับ
การตอบกลับสคีมาของเครื่องมือเดียวภายในโปรแกรมได้

รันไทม์เกสต์ไม่เคยมองเห็นออบเจ็กต์ของโฮสต์โดยตรง อินพุตและเอาต์พุตข้าม
บริดจ์ในรูปค่าที่เข้ากันได้กับ JSON พร้อมขีดจำกัดขนาดที่ชัดเจน

## เนมสเปซภายใน

เนมสเปซภายในมอบ API โดเมนแบบกระชับให้โหมดโค้ดโดยไม่เพิ่มเครื่องมือ
ที่โมเดลมองเห็น อินทิเกรชันที่โหลดเดอร์เป็นเจ้าของจะลงทะเบียนเนมสเปซ เช่น
`Issues` หรือ `Calendar`; จากนั้นโค้ดเกสต์จะเรียกเนมสเปซนั้น
ภายในโปรแกรม QuickJS ขณะที่โมเดลยังคงเห็นพื้นผิวควบคุม/โดยตรงแบบกะทัดรัด

ขณะนี้เนมสเปซเป็นแบบภายใน ยังไม่มี API เนมสเปซของ SDK Plugin สาธารณะ:
เนมสเปซของ Plugin ภายนอกจำเป็นต้องมีสัญญาที่โหลดเดอร์เป็นเจ้าของ เพื่อให้ข้อมูลประจำตัว
ของ Plugin ไฟล์รายการที่ติดตั้ง สถานะการยืนยันตัวตน และตัวอธิบายแค็ตตาล็อกที่แคชไว้
ไม่คลาดเคลื่อนจากเครื่องมือ Plugin ที่รองรับเนมสเปซนั้น โหมดโค้ดของแกนหลักเป็นเจ้าของ
เฉพาะแซนด์บ็อกซ์ การทำซีเรียลไลซ์ การควบคุมแค็ตตาล็อก และการส่งต่อผ่านบริดจ์

โค้ดเกสต์ใช้ได้ทั้งโกลบอลโดยตรงหรือแมป `namespaces`:

```javascript
const open = await Issues.list({ state: "open" });
const alsoOpen = await namespaces.Issues.list({ state: "open" });
return { count: open.length, alsoCount: alsoOpen.length };
```

### วงจรชีวิตของรีจิสทรี

รีจิสทรีเนมสเปซอยู่ภายในโปรเซสและใช้ ID เนมสเปซเป็นคีย์:

1. โหลดเดอร์ที่เชื่อถือได้เรียก `registerCodeModeNamespaceForPlugin(pluginId, registration)`
2. โหมดโค้ดสร้าง `ToolSearchRuntime` ที่ซ่อนไว้สำหรับการรันและอ่าน
   แค็ตตาล็อกตามขอบเขตการรันของรายการนั้น
3. `createCodeModeNamespaceRuntime(ctx, catalog)` เก็บเฉพาะการลงทะเบียน
   ที่ `requiredToolNames` ทั้งหมดมองเห็นได้และเป็นของ `pluginId` เดียวกัน
4. แต่ละเนมสเปซที่มองเห็นได้เรียก `createScope(ctx)` สำหรับการรันปัจจุบัน
   โดยรับบริบทการรัน เช่น `agentId`, `sessionKey`, `sessionId`,
   `runId`, การกำหนดค่า และสถานะยกเลิก
5. ข้อมูลขอบเขตถูกทำซีเรียลไลซ์เป็นตัวอธิบายแบบธรรมดาและแทรกลงใน QuickJS
   เป็นโกลบอลโดยตรงและ `namespaces.<globalName>`
6. การเรียกของเกสต์หยุดรอผ่านบริดจ์เวิร์กเกอร์ แก้ไขพาธเนมสเปซ
   บนโฮสต์ แมปการเรียกไปยังเครื่องมือแค็ตตาล็อกที่ประกาศและ Plugin เป็นเจ้าของ
   แล้วเรียกใช้เครื่องมือนั้นผ่าน `ToolSearchRuntime.callExactId`
7. การเรียกบริดจ์เนมสเปซที่พร้อมจะถูกระบายโดยอัตโนมัติภายในการเรียก
   `exec`/`wait` ที่ใช้งานอยู่; หากงานเนมสเปซยังค้างอยู่เมื่อหมดเวลา
   หรือเกสต์ยอมคืนการทำงานอย่างชัดเจน `wait` จะดำเนินรันไทม์เนมสเปซเดิม
   ต่อในภายหลัง
8. การย้อนกลับหรือถอนการติดตั้ง Plugin จะเรียก
   `clearCodeModeNamespacesForPlugin(pluginId)` เพื่อไม่ให้โกลบอลที่ล้าสมัย
   คงอยู่หลังการโหลด Plugin ล้มเหลว

การเรียกเนมสเปซคือการเรียกเครื่องมือแค็ตตาล็อก โดยใช้นโยบาย ฮุก
การอนุมัติ การจัดการการยกเลิก เทเลเมทรี การฉายทรานสคริปต์ และพฤติกรรม
หยุดรอ/ดำเนินการต่อแบบเดียวกับ `tools.call(...)`

### รูปแบบการลงทะเบียน

ลงทะเบียนเนมสเปซจากอินทิเกรชันที่เป็นเจ้าของเครื่องมือเบื้องหลัง จำกัดขอบเขต
ให้เล็กและเปิดเผยเฉพาะกริยาของโดเมนที่แมปกับเครื่องมือแค็ตตาล็อกที่ประกาศไว้

```typescript
import {
  createCodeModeNamespaceTool,
  registerCodeModeNamespaceForPlugin,
} from "../agents/code-mode-namespaces.js";

const pluginId = "github";

registerCodeModeNamespaceForPlugin(pluginId, {
  id: "github-issues",
  globalName: "Issues",
  description: "ตัวช่วย GitHub issue สำหรับรีโพซิทอรีปัจจุบัน",
  requiredToolNames: ["github_list_issues", "github_update_issue"],
  prompt: "ใช้ Issues.list(params) และ Issues.update(number, patch)",
  createScope: (ctx) => ({
    repository: ctx.config,
    list: createCodeModeNamespaceTool("github_list_issues", ([params]) => params ?? {}),
    update: createCodeModeNamespaceTool("github_update_issue", ([number, patch]) => ({
      number,
      patch,
    })),
  }),
});
```

`createCodeModeNamespaceTool(toolName, inputMapper)` ทำเครื่องหมายสมาชิกขอบเขตเป็น
ฟังก์ชันเนมสเปซที่เรียกใช้ได้ `inputMapper` ซึ่งเป็นตัวเลือกจะรับอาร์กิวเมนต์
ของเกสต์และส่งคืนออบเจ็กต์อินพุตสำหรับเครื่องมือแค็ตตาล็อกเบื้องหลัง; หากไม่มี
จะใช้อาร์กิวเมนต์แรกของเกสต์ หรือใช้ `{}` เมื่อไม่ได้ระบุ

ฟังก์ชันโฮสต์ดิบจะถูกปฏิเสธก่อนโค้ดเกสต์ทำงาน:

```typescript
createScope: () => ({
  // ไม่ถูกต้อง: การทำเช่นนี้ข้ามวงจรชีวิตของเครื่องมือแค็ตตาล็อกและจะถูกปฏิเสธ
  list: async () => githubClient.listIssues(),
});
```

### ความเป็นเจ้าของและการมองเห็น

ความเป็นเจ้าของเนมสเปซผูกกับ `pluginId` ของผู้เรียกลงทะเบียน
`requiredToolNames` เป็นทั้งด่านควบคุมการมองเห็นและการตรวจสอบความเป็นเจ้าของ:

- เครื่องมือที่จำเป็นทุกชิ้นต้องมีอยู่ในแค็ตตาล็อกของการรัน
- เครื่องมือที่จำเป็นทุกชิ้นต้องมี `sourceName === pluginId`
- เนมสเปซจะถูกซ่อนเมื่อเครื่องมือที่จำเป็นรายการใดขาดหายไปหรือเป็นของ
  Plugin อื่น
- แต่ละพาธที่เรียกใช้ได้สามารถกำหนดเป้าหมายได้เฉพาะเครื่องมือที่ระบุชื่อไว้ใน `requiredToolNames`

วิธีนี้ป้องกันไม่ให้ Plugin อื่นเปิดเผยเนมสเปซด้วยการลงทะเบียนเครื่องมือ
ชื่อเดียวกัน และทำให้เนมสเปซสอดคล้องกับนโยบายเอเจนต์ทั่วไป: หากการรัน
มองไม่เห็นเครื่องมือเบื้องหลัง ก็จะมองไม่เห็นเนมสเปซเช่นกัน

ตัวอย่างเช่น เนมสเปซ GitHub ควรอยู่หลัง Plugin ที่ GitHub เป็นเจ้าของ ซึ่งเป็นเจ้าของ
การยืนยันตัวตน GitHub, ไคลเอนต์ REST/GraphQL, ขีดจำกัดอัตรา, การอนุมัติการเขียน
และการทดสอบ โหมดโค้ดของแกนหลักไม่ควรฝัง API เฉพาะ GitHub, การจัดการโทเค็น
หรือนโยบายผู้ให้บริการ

### กฎการทำซีเรียลไลซ์ขอบเขต

`createScope(ctx)` อาจส่งคืนออบเจ็กต์ธรรมดาที่มีค่าซึ่งเข้ากันได้กับ JSON,
อาร์เรย์ ออบเจ็กต์แบบซ้อน และมาร์กเกอร์การเรียก `createCodeModeNamespaceTool(...)`
ออบเจ็กต์โฮสต์จะไม่เข้าสู่ QuickJS โดยตรง

ตัวทำซีเรียลไลซ์จะปฏิเสธ:

- ฟังก์ชันดิบ
- กราฟออบเจ็กต์แบบวนรอบ
- เซกเมนต์พาธที่ไม่ปลอดภัย: `__proto__`, `constructor`, `prototype`, คีย์ว่าง
  หรือคีย์ที่มีตัวคั่นพาธภายใน
- ค่า `globalName` ที่ไม่ใช่ตัวระบุ JavaScript
- การชนกันของ `globalName` กับโกลบอลในตัวของโหมดโค้ด เช่น `tools`,
  `namespaces`, `text`, `json`, `yield_control`, `MCP`, `API`, `ALL_TOOLS` หรือ
  `__openclaw*`

ค่าที่ไม่สามารถทำซีเรียลไลซ์เป็น JSON ได้จะถูกแปลงเป็นค่าทางเลือกที่ปลอดภัยต่อ JSON
ก่อนข้ามบริดจ์ ข้อมูลไบนารี แฮนเดิล ซ็อกเก็ต ไคลเอนต์ และอินสแตนซ์คลาส
ควรอยู่หลังเครื่องมือแค็ตตาล็อกทั่วไป

### พรอมต์

`description` ของเนมสเปซและ `prompt` ซึ่งเป็นตัวเลือกจะถูกเพิ่มต่อท้ายสคีมา
`exec` ที่โมเดลมองเห็นเฉพาะเมื่อเนมสเปซมองเห็นได้สำหรับการรันนั้น ใช้
สิ่งเหล่านี้เพื่อสอนพื้นผิวที่มีประโยชน์ขนาดเล็กที่สุด:

```typescript
{
  description: "ตัวช่วยสำหรับบริการผลิตนิยาย",
  prompt:
    "ใช้ Fictions.riskAudit(), Fictions.promoteIfReady(id, status) และ Fictions.unpaidOver(amount)",
}
```

กำหนดให้พรอมต์กล่าวถึงสัญญาของเนมสเปซ ไม่ใช่การตั้งค่าการยืนยันตัวตน ประวัติการติดตั้งใช้งาน
หรือพฤติกรรมของ Plugin ที่ไม่เกี่ยวข้อง

### การล้างข้อมูล

เนมสเปซเป็นการลงทะเบียนภายในโปรเซส ให้ลบออกเมื่อ Plugin เจ้าของ
ถูกปิดใช้งาน ถอนการติดตั้ง หรือย้อนกลับ:

```typescript
clearCodeModeNamespacesForPlugin(pluginId);
```

การล้างข้อมูลโหมดโค้ดเป็นหน้าที่ของ Plugin ให้ล้างการลงทะเบียนเนมสเปซของ Plugin
เมื่อวงจรชีวิตสิ้นสุดลง แทนที่จะเก็บแฮนเดิลสำหรับรื้อถอนแยกตามเนมสเปซ
การทดสอบสามารถเรียก `clearCodeModeNamespacesForTest()` เพื่อหลีกเลี่ยงการรั่วไหลของ
การลงทะเบียนระหว่างกรณีทดสอบ

### รายการตรวจสอบการทดสอบ

การเปลี่ยนแปลงเนมสเปซควรครอบคลุมขอบเขตความปลอดภัยและพฤติกรรมของเกสต์:

- ข้อความพรอมต์ของเนมสเปซปรากฏเฉพาะเมื่อมองเห็นเครื่องมือเบื้องหลัง
- เครื่องมือชื่อเดียวกันจาก `sourceName` อื่นต้องไม่เปิดเผยเนมสเปซ
- ฟังก์ชันขอบเขตดิบถูกปฏิเสธ
- รหัสเนมสเปซปลอมและพาธปลอมถูกปฏิเสธ
- พาธที่เรียกได้ต้องไม่กำหนดเป้าหมายไปยังเครื่องมือที่ไม่ได้ประกาศ
- ออบเจ็กต์ซ้อนและการอ้างอิงร่วมถูกทำให้เป็นอนุกรมอย่างถูกต้อง
- การเรียกเนมสเปซทำงานผ่านเครื่องมือในแค็ตตาล็อกและส่งคืนรายละเอียดที่ปลอดภัยสำหรับ JSON
- โค้ดเกสต์สามารถดักจับความล้มเหลวได้
- การเรียกเนมสเปซที่ถูกระงับดำเนินต่อผ่าน `wait`
- การย้อนกลับ Plugin ล้างการลงทะเบียนเนมสเปซของเจ้าของ

เนมสเปซช่วยเสริมแค็ตตาล็อก `tools.search`/`tools.call` แบบทั่วไป: ใช้
แค็ตตาล็อกสำหรับเครื่องมือ OpenClaw, Plugin และไคลเอนต์ที่เปิดใช้งานโดยพลการ ใช้ `MCP`
สำหรับเครื่องมือ MCP และใช้เนมสเปซอื่นสำหรับ API โดเมนที่มีเอกสารกำกับและ Plugin เป็นเจ้าของ
เมื่อโค้ดที่กระชับเชื่อถือได้มากกว่าการค้นหาสคีมาซ้ำๆ

## API เอาต์พุต

- `text(value)` เพิ่มเอาต์พุตที่มนุษย์อ่านได้ต่อท้ายอาร์เรย์ `output`
- `json(value)` เพิ่มรายการเอาต์พุตแบบมีโครงสร้างต่อท้ายหลังจาก
  ทำให้เป็นอนุกรมที่เข้ากันได้กับ JSON
- ค่าสุดท้ายที่โค้ดเกสต์ส่งคืนจะกลายเป็น `value` ในผลลัพธ์ `completed`

```typescript
type CodeModeOutput = { type: "text"; text: string } | { type: "json"; value: unknown };
```

กฎ: ลำดับเอาต์พุตตรงกับลำดับการเรียกของเกสต์ เอาต์พุตถูกจำกัดด้วย
`maxOutputBytes` ค่าที่ทำให้เป็นอนุกรมไม่ได้จะถูกแปลงเป็นสตริงธรรมดาหรือ
ข้อผิดพลาด ไม่รองรับค่าไบนารี รูปภาพและไฟล์ส่งผ่าน
เครื่องมือ OpenClaw ตามปกติ ไม่ใช่ผ่านบริดจ์โหมดโค้ด

## แค็ตตาล็อกเครื่องมือ

แค็ตตาล็อกที่ซ่อนไว้ประกอบด้วยเครื่องมือหลังการกรองตามนโยบายที่มีผล ตามลำดับ
ดังนี้: เครื่องมือหลักของ OpenClaw, เครื่องมือ Plugin ที่รวมมาให้, เครื่องมือ Plugin ภายนอก, เครื่องมือ MCP
แล้วจึงเป็นเครื่องมือที่ไคลเอนต์จัดเตรียมให้สำหรับการรันปัจจุบัน

รหัสแค็ตตาล็อกมีความเสถียรภายในการรันหนึ่งครั้งและกำหนดได้แน่นอนสำหรับ
ชุดเครื่องมือที่เทียบเท่ากันเมื่อเป็นไปได้ รูปแบบจริง:

```text
<source>:<owner>:<tool-name>
```

โดย `<source>` คือ `openclaw`, `mcp` หรือ `client` (เครื่องมือ Plugin ใช้
`openclaw` โดยมีรหัส Plugin เป็น `<owner>` ส่วนเครื่องมือหลักใช้ `openclaw:core:*`)
ตัวอย่าง:

```text
openclaw:core:message
openclaw:browser:browser_request
mcp:github:create_issue
client:app:select_file
```

แค็ตตาล็อกละเว้นเครื่องมือควบคุมโหมดโค้ด (`exec`, `wait`, `tool_search_code`,
`tool_search`, `tool_describe`, `tool_call`) และเครื่องมือที่เรียกโดยตรงเท่านั้น ตัวควบคุม
ต้องไม่เรียกซ้ำผ่านแค็ตตาล็อก ส่วนเครื่องมือที่เรียกโดยตรงเท่านั้นยังคงมองเห็นได้โดยโมเดล
เนื่องจากผลลัพธ์แบบมีโครงสร้างไม่สามารถข้ามบริดจ์ QuickJS ได้

รายการ MCP ยังคงอยู่ในแค็ตตาล็อกที่มีขอบเขตระดับการรัน เพื่อให้นโยบาย การอนุมัติ ฮุก
เทเลเมทรี การฉายทรานสคริปต์ และรหัสเครื่องมือที่แน่นอนยังคงใช้ร่วมกับ
การเรียกใช้เครื่องมือตามปกติ มุมมองสำหรับเกสต์ `ALL_TOOLS`, `tools.search(...)`,
`tools.describe(...)`, `tools.callValue(...)` และ `tools.call(...)` จะละเว้นรายการ MCP เนมสเปซ
`MCP.<server>.<tool>({ ...input })` ที่สร้างขึ้นจะแก้กลับไปยัง
รหัสแค็ตตาล็อกที่แน่นอนและส่งต่อผ่านพาธตัวดำเนินการเดียวกัน

## การทำงานร่วมกับการค้นหาเครื่องมือ

โหมดโค้ดใช้แทนพื้นผิวโมเดลการค้นหาเครื่องมือของ OpenClaw สำหรับการรันที่
เปิดใช้งานโหมดนี้

เมื่อ `tools.codeMode.enabled` เป็น true และโหมดโค้ดทำงาน:

- OpenClaw จะไม่เปิดเผย `tool_search_code`, `tool_search`, `tool_describe`
  หรือ `tool_call` เป็นเครื่องมือที่โมเดลมองเห็นได้
- แนวคิดการจัดทำแค็ตตาล็อกเดียวกันย้ายเข้าไปอยู่ภายในรันไทม์ของเกสต์
- รันไทม์ของเกสต์ได้รับเมทาดาทา `ALL_TOOLS` แบบกระชับและตัวช่วยค้นหา/อธิบาย/
  เรียกใช้สำหรับเครื่องมือที่ไม่ใช่ MCP
- การเรียก MCP ใช้เนมสเปซ `MCP` ที่สร้างขึ้นและส่วนหัว `$api()` ของเนมสเปซนั้น
  แทน `tools.call(...)`
- การเรียกซ้อนส่งต่อผ่านพาธตัวดำเนินการ OpenClaw เดียวกับที่การค้นหา
  เครื่องมือใช้

ดู [การค้นหาเครื่องมือ](/th/tools/tool-search) สำหรับบริดจ์แค็ตตาล็อกแบบกระชับของ OpenClaw
ซึ่งโหมดโค้ดใช้แทนในการรันที่เปิดใช้งาน

## ชื่อเครื่องมือและการชนกัน

เครื่องมือ `exec` ที่โมเดลมองเห็นได้คือเครื่องมือโหมดโค้ด หากเปิดใช้งานเครื่องมือเชลล์
`exec` ตามปกติของ OpenClaw เครื่องมือนี้จะถูกซ่อนจากโมเดลและจัดเข้าแค็ตตาล็อกเหมือน
เครื่องมืออื่นๆ

ภายในรันไทม์ของเกสต์:

- `tools.call("openclaw:core:exec", input)` สามารถเรียกเครื่องมือเชลล์ exec ได้หาก
  นโยบายอนุญาต
- `tools.exec(...)` จะถูกติดตั้งเฉพาะเมื่อรายการเชลล์ exec ในแค็ตตาล็อกมี
  ชื่อที่ปลอดภัยและไม่กำกวม
- เครื่องมือโหมดโค้ด `exec` จะไม่สามารถเรียกซ้ำผ่าน `tools` ได้

หากเครื่องมือสองรายการถูกปรับให้เป็นชื่ออำนวยความสะดวกที่ปลอดภัยชื่อเดียวกัน OpenClaw จะละเว้น
ฟังก์ชันอำนวยความสะดวกและกำหนดให้ใช้ `tools.call(id, input)`

## การเรียกใช้เครื่องมือซ้อน

การเรียกใช้เครื่องมือซ้อนทุกครั้งจะข้ามบริดจ์ของโฮสต์และกลับเข้าสู่ OpenClaw
โดยคงไว้ซึ่ง: รหัสเอเจนต์ที่ทำงานอยู่ รหัสและคีย์เซสชัน บริบทผู้ส่งและช่องทาง
นโยบายแซนด์บ็อกซ์ นโยบายการอนุมัติ ฮุก `before_tool_call` ของ Plugin สัญญาณ
ยกเลิก การอัปเดตแบบสตรีมเมื่อพร้อมใช้งาน และเหตุการณ์เส้นทาง/การตรวจสอบ

การเรียกซ้อนจะถูกฉายเข้าไปในทรานสคริปต์เป็นการเรียกเครื่องมือจริง เพื่อให้บันเดิล
การสนับสนุนแสดงสิ่งที่เกิดขึ้น โดยการฉายจะระบุการเรียกเครื่องมือโหมดโค้ดแม่
และรหัสเครื่องมือซ้อน

อนุญาตการเรียกซ้อนแบบขนานได้สูงสุด `maxPendingToolCalls`

## วงจรชีวิตการรันและสแนปช็อต

การรันโหมดโค้ดแต่ละครั้งถูกติดตามในแมปภายในโปรเซสโดยใช้ `runId` เป็นคีย์ (ไม่
บันทึกลงดิสก์หรือฐานข้อมูล) `exec`/`wait` ส่งคืนสถานะผลลัพธ์หนึ่งในสามแบบ:
`completed`, `waiting` หรือ `failed`

- ผลลัพธ์ `waiting` เก็บสแนปช็อต QuickJS คำขอบริดจ์ที่รอดำเนินการ และ
  เมทาดาทาขอบเขต (รหัสการรันของเอเจนต์ รหัส/คีย์เซสชัน) ไว้จนกว่า `wait` จะดำเนินต่อหรือ
  หมดอายุ
- การหมดอายุ เซสชันผิด การรันผิด และค่า `runId` ที่ไม่รู้จัก/กำลังดำเนินต่อแล้ว
  จะไม่สร้างสถานะสิ้นสุดที่แยกต่างหาก แต่จะแสดงเป็น
  ผลลัพธ์ `failed` (`code: "invalid_input"`) พร้อมข้อความ เช่น `code mode
run is unavailable or expired.` หรือ `code mode run belongs to a different
session.`
- สแนปช็อตของการรันจะถูกลบออกจากแมปทันทีที่สิ้นสุดเป็น
  `completed` หรือ `failed` หรือถูกทิ้งเมื่อ Gateway ปิดตัว (ไม่มีสิ่งใด
  คงอยู่หลังการรีสตาร์ต เนื่องจากเป็นสถานะรันไทม์ชั่วคราว)
- สำหรับงานแบบอ่านอย่างเดียว `exec` สามารถตั้งค่า `restartSafe: true` จากนั้น OpenClaw จะปฏิเสธ
  การเรียกแค็ตตาล็อกและเนมสเปซ Plugin ที่มีผลข้างเคียงก่อนดำเนินการ และ
  ทำเครื่องหมายผลลัพธ์ที่ถูกระงับว่าปลอดภัยสำหรับการเล่นซ้ำ หากการรีสตาร์ตขัดจังหวะ `wait`,
  [การกู้คืนหลังรีสตาร์ต](/th/gateway/restart-recovery) จะสร้างเทิร์นขึ้นใหม่จาก
  ทรานสคริปต์ แทนการกู้คืนสแนปช็อตภายในโปรเซส ตัวเทิร์นการกู้คืนเอง
  ยังคงจำกัดเฉพาะเครื่องมือหลักแบบอ่านอย่างเดียวที่ผ่านการตรวจสอบและเครื่องมือ Plugin
  ที่ระบุอย่างชัดเจนว่าปลอดภัยสำหรับการเล่นซ้ำ
- OpenClaw จำกัดจำนวนการรันที่ถูกระงับพร้อมกันต่อโปรเซสไว้ที่ (64) และ
  ปฏิเสธการระงับใหม่ที่เกินขีดจำกัดดังกล่าวด้วย `too many suspended code mode
runs.`

พื้นที่จัดเก็บสแนปช็อตถูกจำกัดด้วย `maxSnapshotBytes` ต่อการรัน ขีดจำกัดการรัน
ที่ถูกระงับต่อโปรเซสข้างต้น และ `snapshotTtlSeconds`

## รันไทม์ QuickJS-WASI

OpenClaw โหลด `quickjs-wasi` เป็นการขึ้นต่อกันโดยตรงในแพ็กเกจเจ้าของ โดย
ไม่พึ่งพาสำเนาแบบส่งผ่านที่ติดตั้งไว้สำหรับการขึ้นต่อกันที่ไม่เกี่ยวข้อง

ความรับผิดชอบของรันไทม์: คอมไพล์/โหลดโมดูล WebAssembly ของ QuickJS-WASI
สร้าง VM แยกหนึ่งรายการต่อการรันหรือการดำเนินต่อของโหมดโค้ด ลงทะเบียนคอลแบ็กโฮสต์
ด้วยชื่อที่เสถียร ตั้งค่าขีดจำกัดหน่วยความจำและการขัดจังหวะ ประเมิน JavaScript ระบาย
งานที่รอดำเนินการ ทำสแนปช็อตสถานะ VM ที่ถูกระงับ กู้คืนสแนปช็อตสำหรับ `wait`
และกำจัดแฮนเดิล VM กับสแนปช็อตหลังจากสถานะสิ้นสุด

รันไทม์ทำงานในเธรดผู้ปฏิบัติงานของ Node.js นอกลูปเหตุการณ์หลักของ OpenClaw
ลูปไม่รู้จบของเกสต์ต้องไม่บล็อกโปรเซส Gateway อย่างไม่มีกำหนด
ตัวจัดการการขัดจังหวะของผู้ปฏิบัติงานบังคับใช้การหมดเวลาตามเวลาจริง
โดยไม่ขึ้นกับความร่วมมือของโค้ดเกสต์

## TypeScript

การรองรับ TypeScript เป็นเพียงการแปลงซอร์ส: อินพุตที่ยอมรับคือสตริงโค้ด
TypeScript หนึ่งรายการ เอาต์พุตคือสตริง JavaScript ที่ QuickJS-WASI ประเมินผล
ไม่มีการตรวจสอบชนิด ไม่มีการแก้ไขโมดูล และไม่มี
`import`/`require` การวินิจฉัยจะถูกส่งคืนเป็นผลลัพธ์ `failed`

คอมไพเลอร์ TypeScript จะโหลดแบบล่าช้าเฉพาะเซลล์ TypeScript เท่านั้น เซลล์
JavaScript ธรรมดาและโหมดโค้ดที่ปิดใช้งานจะไม่โหลดคอมไพเลอร์

## ขอบเขตความปลอดภัย

โค้ดของโมเดลถือว่าเป็นภัยคุกคาม รันไทม์ใช้การป้องกันหลายชั้น:

- รัน QuickJS-WASI นอกลูปเหตุการณ์หลัก ในเธรดผู้ปฏิบัติงาน
- โหลด `quickjs-wasi` เป็นการขึ้นต่อกันโดยตรง ไม่ผ่าน Codex หรือ
  แพ็กเกจแบบส่งผ่าน
- ไม่มีระบบไฟล์ เครือข่าย โปรเซสย่อย การนำเข้าโมดูล ตัวแปรสภาพแวดล้อม
  หรือออบเจ็กต์โกลบอลของโฮสต์ภายในเกสต์
- ใช้ขีดจำกัดหน่วยความจำและการขัดจังหวะของ QuickJS ร่วมกับการหมดเวลา
  ตามเวลาจริงของโปรเซสแม่
- บังคับใช้ขีดจำกัดเอาต์พุต สแนปช็อต บันทึก และการเรียกที่รอดำเนินการ
- ทำให้ค่าบริดจ์ของโฮสต์เป็นอนุกรมผ่านอะแดปเตอร์ JSON ที่จำกัด
- แปลงข้อผิดพลาดของโฮสต์เป็นข้อผิดพลาดธรรมดาของเกสต์ โดยไม่ส่งออบเจ็กต์จากขอบเขตโฮสต์
- ทิ้งสแนปช็อตเมื่อหมดเวลา ถูกยกเลิก เซสชันสิ้นสุด หรือหมดอายุ
- ปฏิเสธการเข้าถึงแบบเรียกซ้ำไปยัง `exec`, `wait` และเครื่องมือควบคุมการค้นหาเครื่องมือ
- ป้องกันไม่ให้การชนกันของชื่ออำนวยความสะดวกบดบังตัวช่วยแค็ตตาล็อก

แซนด์บ็อกซ์เป็นชั้นความปลอดภัยหนึ่งชั้น ผู้ดำเนินการอาจยังต้องใช้
การเสริมความแข็งแกร่งระดับระบบปฏิบัติการสำหรับการติดตั้งใช้งานที่มีความเสี่ยงสูง

## รหัสข้อผิดพลาด

```typescript
type CodeModeErrorCode =
  | "invalid_input"
  | "runtime_unavailable"
  | "timeout"
  | "output_limit_exceeded"
  | "snapshot_limit_exceeded"
  | "internal_error";
```

`invalid_input` ครอบคลุมอาร์กิวเมนต์ `exec`/`wait` ที่ไม่ถูกต้อง ภาษาที่ปิดใช้งาน
การเข้าถึงโมดูลที่ถูกปฏิเสธ ความล้มเหลวในการแปลง TypeScript ค่า `runId`
ที่ไม่รู้จัก/หมดอายุ/อยู่นอกขอบเขต และการรันที่ถูกระงับมากเกินไป `runtime_unavailable`
ครอบคลุมผู้ปฏิบัติงาน QuickJS ที่เริ่มทำงานไม่สำเร็จหรือออกด้วยสถานะไม่เป็นศูนย์

ข้อผิดพลาดที่ส่งคืนให้เกสต์เป็นข้อมูลธรรมดา อินสแตนซ์ `Error` ของโฮสต์ ออบเจ็กต์
สแต็ก โปรโตไทป์ และฟังก์ชันของโฮสต์จะไม่ข้ามเข้าไปใน QuickJS

## เทเลเมทรี

ฟิลด์ `telemetry` ของแต่ละผลลัพธ์รายงาน: ขนาดแค็ตตาล็อกที่ซ่อนอยู่และการแจกแจง
ตามแหล่งที่มา (จำนวน `openclaw`/`mcp`/`client`) จำนวนการค้นหา/อธิบาย/เรียกใช้
สะสมสำหรับแค็ตตาล็อกของการรัน และชื่อเครื่องมือที่โมเดลมองเห็นได้ (`exec`,
`wait` และเครื่องมือที่เรียกโดยตรงเท่านั้นซึ่งเก็บไว้)

เทเลเมทรีต้องไม่มีข้อมูลลับ ค่าสภาพแวดล้อมดิบ หรืออินพุตเครื่องมือที่ไม่ได้ปกปิด
นอกเหนือจากนโยบายเส้นทางที่มีอยู่ของ OpenClaw

## การแก้จุดบกพร่อง

ใช้การบันทึกการขนส่งของโมเดลแบบเจาะจง เมื่อโหมดโค้ดทำงานแตกต่างจาก
การรันเครื่องมือตามปกติ:

```bash
OPENCLAW_DEBUG_CODE_MODE=1 \
OPENCLAW_DEBUG_MODEL_TRANSPORT=1 \
OPENCLAW_DEBUG_MODEL_PAYLOAD=tools \
OPENCLAW_DEBUG_SSE=events \
openclaw gateway
```

สำหรับการดีบักรูปแบบ payload ให้ใช้ `OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted`
คำสั่งนี้จะบันทึกสแนปช็อต JSON ของคำขอโมเดลที่ผ่านการปกปิดข้อมูลและจำกัดขนาดไว้แล้ว ให้ใช้เฉพาะ
ระหว่างการดีบักเท่านั้น เนื่องจากพรอมป์และข้อความในสารยังอาจปรากฏอยู่

สำหรับการดีบักสตรีม ให้ใช้ `OPENCLAW_DEBUG_SSE=peek` เพื่อบันทึกเหตุการณ์ SSE 5 รายการแรก
ที่ผ่านการปกปิดข้อมูลแล้ว Code mode จะปฏิเสธการทำงานเช่นกัน หาก payload สุดท้ายของผู้ให้บริการ
ไม่มี `exec` จำนวนหนึ่งรายการ, `wait` จำนวนหนึ่งรายการ และมีเฉพาะเครื่องมือ
แบบ direct-only ที่ได้รับอนุมัติ หลังจากพื้นผิว Code mode เปิดใช้งานแล้ว

## โครงสร้างการใช้งาน

- สัญญาการกำหนดค่า: `tools.codeMode`
- ตัวสร้างแค็ตตาล็อก: แปลงเครื่องมือที่มีผลเป็นรายการแบบย่อและแมป id
- อะแดปเตอร์พื้นผิวโมเดล: แทนที่เครื่องมือที่มองเห็นได้ด้วยเครื่องมือควบคุม/เครื่องมือโดยตรง
- อะแดปเตอร์รันไทม์ QuickJS-WASI: โหลด ประเมิน สร้างสแนปช็อต กู้คืน และกำจัด
- ตัวควบคุม worker: การหมดเวลา การยกเลิก และการแยกความขัดข้อง
- อะแดปเตอร์บริดจ์: คอลแบ็กโฮสต์ที่ปลอดภัยสำหรับ JSON และการส่งมอบผลลัพธ์
- อะแดปเตอร์แปลง TypeScript
- ที่เก็บสแนปช็อต: TTL ขีดจำกัดขนาด และการกำหนดขอบเขตตามรอบการทำงาน/เซสชัน
- การฉายวิถีสำหรับการเรียกเครื่องมือแบบซ้อน
- ตัวนับเทเลเมทรีและการวินิจฉัย

การใช้งานนี้นำแนวคิดแค็ตตาล็อกและตัวดำเนินการจาก Tool Search มาใช้ซ้ำ แต่
ไม่ได้ใช้ลูก `node:vm` เป็นแซนด์บ็อกซ์

## รายการตรวจสอบการตรวจสอบความถูกต้อง

ความครอบคลุมของ Code mode ควรพิสูจน์ว่า:

- การกำหนดค่าที่ปิดใช้งานจะไม่เปลี่ยนการเปิดเผยเครื่องมือที่มีอยู่
- การกำหนดค่าแบบออบเจ็กต์ที่ไม่มี `enabled: true` จะยังคงปิดใช้งาน Code mode
- การกำหนดค่าที่เปิดใช้งานจะเปิดเผย `exec`, `wait` และเฉพาะเครื่องมือ direct-only ที่จำเป็น
  ให้แก่โมเดลเมื่อเครื่องมือทำงานอยู่ในรอบการทำงาน
- รอบการทำงานแบบดิบที่ไม่มีเครื่องมือ, `disableTools` และรายการอนุญาตที่ว่างเปล่า จะไม่ทริกเกอร์
  การบังคับใช้ payload ของ Code mode
- เครื่องมือที่มีผลซึ่งไม่ใช่ MCP และมีสิทธิ์อยู่ในแค็ตตาล็อกทั้งหมดจะปรากฏใน `ALL_TOOLS`
- เครื่องมือ direct-only จะยังคงมองเห็นได้สำหรับโมเดลและไม่ปรากฏใน `ALL_TOOLS`
- เครื่องมือที่ถูกปฏิเสธจะไม่ปรากฏใน `ALL_TOOLS`
- `tools.search`, `tools.describe`, `tools.callValue` และ `tools.call` ใช้งานกับเครื่องมือ OpenClaw ได้
- `API.list("mcp")` และ `API.read("mcp/<server>.d.ts")` เปิดเผย
  การประกาศ MCP ในรูปแบบ TypeScript โดยไม่มีการเรียกบริดจ์/เครื่องมือ
- เนมสเปซ MCP `$api()` ยังคงพร้อมใช้งานเป็นทางเลือกสำรองแบบอินไลน์สำหรับสคีมา
- การเรียกเนมสเปซ MCP ใช้งานได้กับเครื่องมือ MCP ที่มองเห็นได้โดยใช้อินพุตออบเจ็กต์หนึ่งรายการ ขณะที่
  ไม่มีรายการแค็ตตาล็อก MCP โดยตรงใน `tools.*`
- เครื่องมือควบคุมของ Tool Search ถูกซ่อนจากทั้งพื้นผิวโมเดลและ
  แค็ตตาล็อกที่ซ่อนอยู่
- การเรียกแบบซ้อนจะรักษาพฤติกรรมการอนุมัติและฮุกไว้
- เชลล์ `exec` ถูกซ่อนจากโมเดล แต่เรียกได้ด้วย id ของแค็ตตาล็อกเมื่อ
  ได้รับอนุญาต
- Code mode แบบเรียกซ้ำ `exec` และ `wait` ไม่สามารถเรียกจากโค้ด guest ได้
- อินพุต TypeScript ถูกแปลงและประเมินโดยไม่โหลด TypeScript ใน
  เส้นทางที่ปิดใช้งานหรือเส้นทาง JavaScript-only
- การเข้าถึง `import`, `require`, ระบบไฟล์ เครือข่าย และสภาพแวดล้อมจะล้มเหลว
- ลูปไม่สิ้นสุดจะหมดเวลาและไม่สามารถบล็อก Gateway ได้
- ความล้มเหลวจากขีดจำกัดหน่วยความจำจะยุติ VM ของ guest
- มีการบังคับใช้ขีดจำกัดเอาต์พุตและสแนปช็อตกับการเรียกที่เสร็จสมบูรณ์และถูกพักไว้
- `wait` ดำเนินการต่อจากสแนปช็อตที่ถูกพักไว้และส่งคืนค่าสุดท้าย
- ค่า `runId` ที่หมดอายุ ถูกยกเลิก อยู่ผิดเซสชัน และไม่รู้จักจะล้มเหลว
- การเล่นทรานสคริปต์ซ้ำและการคงอยู่จะรักษาการเรียกควบคุมของ Code mode
- ทรานสคริปต์และเทเลเมทรีแสดงการเรียกเครื่องมือแบบซ้อนอย่างชัดเจน

## แผนการทดสอบ E2E

เรียกใช้รายการเหล่านี้เป็นการทดสอบการผสานรวมหรือการทดสอบตั้งแต่ต้นจนจบเมื่อเปลี่ยนรันไทม์:

1. เริ่ม Gateway ด้วย `tools.codeMode.enabled: false`
2. ส่งรอบการทำงานของเอเจนต์พร้อมชุดเครื่องมือโดยตรงขนาดเล็ก
3. ยืนยันว่าเครื่องมือที่โมเดลมองเห็นไม่มีการเปลี่ยนแปลง
4. เริ่มระบบใหม่ด้วย `tools.codeMode.enabled: true`
5. ส่งรอบการทำงานของเอเจนต์พร้อมเครื่องมือทดสอบ OpenClaw, Plugin, MCP และไคลเอ็นต์
6. ยืนยันว่ารายการเครื่องมือที่โมเดลมองเห็นคือ `exec`, `wait` และมีเฉพาะเครื่องมือ
   direct-only ที่กำหนดค่าไว้
7. ใน `exec` ให้อ่าน `ALL_TOOLS` และยืนยันว่าเครื่องมือทดสอบที่มีผลและมีสิทธิ์อยู่ในแค็ตตาล็อก
   ปรากฏอยู่ ขณะที่ไม่มีเครื่องมือ direct-only
8. ใน `exec` ให้เรียกเครื่องมือ OpenClaw/Plugin/ไคลเอ็นต์ผ่าน `tools.search`,
   `tools.describe` และ `tools.callValue` (หรือ `tools.call` แบบดิบ)
9. ใน `exec` ให้เรียก `API.list("mcp")` และ `API.read("mcp/<server>.d.ts")` และ
   ยืนยันว่าไฟล์การประกาศอธิบายเครื่องมือ MCP ที่มองเห็นได้
10. ใน `exec` ให้เรียกเครื่องมือ MCP ผ่าน `MCP.<server>.<tool>({ ...input })` และ
    ยืนยันว่าไม่มีรายการแค็ตตาล็อก MCP โดยตรงใน `ALL_TOOLS` และ
    `tools.*`
11. ยืนยันว่าเครื่องมือที่ถูกปฏิเสธไม่มีอยู่และไม่สามารถเรียกด้วย id ที่คาดเดาได้
12. เริ่มการเรียกเครื่องมือแบบซ้อนที่เสร็จสิ้นหลังจาก `exec` ส่งคืน `waiting`
13. เรียก `wait` และยืนยันว่า VM ที่กู้คืนได้รับผลลัพธ์จากเครื่องมือ
14. ยืนยันว่าคำตอบสุดท้ายมีเอาต์พุตที่สร้างขึ้นหลังการกู้คืน
15. ยืนยันว่าการหมดเวลา การยกเลิก และการหมดอายุของสแนปช็อตจะล้างสถานะรันไทม์
16. ส่งออกวิถีและยืนยันว่าการเรียกแบบซ้อนมองเห็นได้ภายใต้การเรียก
    Code mode ระดับแม่

การเปลี่ยนแปลงเฉพาะเอกสารในหน้านี้ยังคงควรเรียกใช้ `pnpm check:docs`

## ที่เกี่ยวข้อง

- [Swarm](/tools/swarm) สำหรับการประสานเอเจนต์แบบกระจายงานจากสคริปต์ Code Mode
- [Tool Search](/th/tools/tool-search)
- [รันไทม์ของเอเจนต์](/th/concepts/agent-runtimes)
- [เครื่องมือ Exec](/th/tools/exec)
- [การเรียกใช้โค้ด](/th/tools/code-execution)
