RPC and API
การออกแบบ API ของ SDK แอป OpenClaw
หน้านี้คือการออกแบบเอกสารอ้างอิง API แบบละเอียดสำหรับ OpenClaw App SDK สาธารณะ โดยตั้งใจแยกออกจาก Plugin SDK
SDK แอปสาธารณะควรสร้างเป็นสองชั้น:
- ไคลเอนต์ Gateway ระดับต่ำที่สร้างขึ้นอัตโนมัติ
- ตัวครอบระดับสูงที่ใช้งานสะดวก พร้อมออบเจ็กต์
OpenClaw,Agent,Session,Run,Task,Artifact,ApprovalและEnvironment
การออกแบบ namespace
namespace ระดับต่ำควรตามทรัพยากรของ Gateway อย่างใกล้ชิด:
oc.agents.list();
oc.agents.get("main");
oc.agents.create(...);
oc.agents.update(...);
oc.sessions.list();
oc.sessions.create(...);
oc.sessions.resolve(...);
oc.sessions.send(...);
oc.sessions.messages(...);
oc.sessions.fork(...);
oc.sessions.compact(...);
oc.sessions.abort(...);
oc.runs.create(...);
oc.runs.get(runId);
oc.runs.events(runId, { after });
oc.runs.wait(runId);
oc.runs.cancel(runId);
oc.tasks.list(); // future API: current SDK throws unsupported
oc.tasks.get(taskId); // future API: current SDK throws unsupported
oc.tasks.cancel(taskId); // future API: current SDK throws unsupported
oc.tasks.events(taskId, { after }); // future API
oc.models.list();
oc.models.status(); // Gateway models.authStatus
oc.tools.list();
oc.tools.invoke("tool-name", { sessionKey, idempotencyKey });
oc.artifacts.list({ runId });
oc.artifacts.get(artifactId, { runId });
oc.artifacts.download(artifactId, { runId });
oc.approvals.list();
oc.approvals.respond(approvalId, ...);
oc.environments.list();
oc.environments.create(...); // future API: current SDK throws unsupported
oc.environments.status(environmentId);
oc.environments.delete(environmentId); // future API: current SDK throws unsupported
ตัวครอบระดับสูงควรคืนออบเจ็กต์ที่ทำให้โฟลว์ทั่วไปใช้งานได้ราบรื่น:
const run = await agent.run(inputOrParams);
await run.cancel();
await run.wait();
for await (const event of run.events()) {
// normalized event stream
}
const artifacts = await run.artifacts.list();
const session = await run.session();
สัญญา event
SDK สาธารณะควรเปิดเผย event ที่มีเวอร์ชัน เล่นซ้ำได้ และถูกทำให้เป็นรูปแบบมาตรฐาน
type OpenClawEvent = {
version: 1;
id: string;
ts: number;
type: OpenClawEventType;
runId?: string;
sessionId?: string;
sessionKey?: string;
taskId?: string;
agentId?: string;
data: unknown;
raw?: unknown;
};
id คือเคอร์เซอร์สำหรับเล่นซ้ำ ผู้บริโภคควรสามารถเชื่อมต่อใหม่ด้วย
events({ after: id }) และรับ event ที่พลาดไปเมื่อการเก็บรักษาอนุญาต
กลุ่ม event มาตรฐานที่แนะนำ:
| Event | ความหมาย |
|---|---|
run.created |
รับการรันแล้ว |
run.queued |
การรันกำลังรอ lane ของเซสชัน, runtime หรือ environment |
run.started |
Runtime เริ่มดำเนินการแล้ว |
run.completed |
การรันเสร็จสมบูรณ์สำเร็จ |
run.failed |
การรันจบลงพร้อมข้อผิดพลาด |
run.cancelled |
การรันถูกยกเลิก |
run.timed_out |
การรันเกินเวลาที่กำหนด |
assistant.delta |
เดลตาข้อความของผู้ช่วย |
assistant.message |
ข้อความผู้ช่วยที่สมบูรณ์หรือข้อความแทนที่ |
thinking.delta |
เดลตาการให้เหตุผลหรือแผน เมื่อ policy อนุญาตให้เปิดเผย |
tool.call.started |
การเรียก tool เริ่มขึ้น |
tool.call.delta |
การเรียก tool สตรีมความคืบหน้าหรือผลลัพธ์บางส่วน |
tool.call.completed |
การเรียก tool คืนค่าสำเร็จ |
tool.call.failed |
การเรียก tool ล้มเหลว |
approval.requested |
การรันหรือ tool ต้องการการอนุมัติ |
approval.resolved |
การอนุมัติได้รับอนุญาต ถูกปฏิเสธ หมดอายุ หรือถูกยกเลิก |
question.requested |
Runtime ขอข้อมูลจากผู้ใช้หรือแอปโฮสต์ |
question.answered |
แอปโฮสต์ให้คำตอบแล้ว |
artifact.created |
มี artifact ใหม่พร้อมใช้งาน |
artifact.updated |
artifact ที่มีอยู่เปลี่ยนแปลง |
session.created |
สร้างเซสชันแล้ว |
session.updated |
metadata ของเซสชันเปลี่ยนแปลง |
session.compacted |
เกิด Compaction ของเซสชัน |
task.updated |
สถานะงานพื้นหลังเปลี่ยนแปลง |
git.branch |
Runtime ตรวจพบหรือเปลี่ยนสถานะ branch |
git.diff |
Runtime สร้างหรือเปลี่ยน diff |
git.pr |
Runtime เปิด อัปเดต หรือลิงก์ pull request |
payload แบบ runtime-native ควรเข้าถึงได้ผ่าน raw แต่แอปไม่ควรต้อง
แยกวิเคราะห์ raw สำหรับ UI ปกติ
สัญญา result
Run.wait() ควรคืน envelope ของผลลัพธ์ที่เสถียร:
type RunResult = {
runId: string;
status: "accepted" | "completed" | "failed" | "cancelled" | "timed_out";
sessionId?: string;
sessionKey?: string;
taskId?: string;
startedAt?: string | number;
endedAt?: string | number;
output?: {
text?: string;
messages?: SDKMessage[];
};
usage?: {
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
costUsd?: number;
};
artifacts?: ArtifactSummary[];
error?: SDKError;
};
ผลลัพธ์ควรเรียบง่ายและเสถียร ค่า timestamp รักษารูปทรงของ Gateway ดังนั้นการรันปัจจุบันที่อิง lifecycle มักรายงานเป็นตัวเลข epoch มิลลิวินาที ขณะที่ adapter อาจยังแสดงสตริง ISO ได้ UI ที่ซับซ้อน, trace ของ tool และ รายละเอียดแบบ runtime-native ควรอยู่ใน event และ artifact
accepted คือผลลัพธ์การรอที่ยังไม่สิ้นสุด: หมายความว่า deadline การรอของ Gateway
หมดลงก่อนที่การรันจะสร้างจุดจบ/error ของ lifecycle ห้ามปฏิบัติต่อค่านี้เป็น
timed_out; timed_out สงวนไว้สำหรับการรันที่เกิน timeout ของ runtime เอง
การอนุมัติและคำถาม
การอนุมัติต้องเป็นองค์ประกอบชั้นหนึ่ง เพราะเอเจนต์เขียนโค้ดข้ามขอบเขตความปลอดภัยอยู่เสมอ
run.onApproval(async (request) => {
if (request.kind === "tool" && request.toolName === "exec") {
return request.approveOnce({ reason: "CI command allowed by policy" });
}
return request.askUser();
});
event การอนุมัติควรมี:
- id การอนุมัติ
- id การรันและ id เซสชัน
- ชนิดคำขอ
- สรุปการกระทำที่ขอ
- ชื่อ tool หรือการกระทำของ environment
- ระดับความเสี่ยง
- การตัดสินใจที่ใช้ได้
- วันหมดอายุ
- การตัดสินใจสามารถนำกลับมาใช้ซ้ำได้หรือไม่
คำถามแยกจากการอนุมัติ คำถามขอข้อมูลจากผู้ใช้หรือแอปโฮสต์ ส่วนการอนุมัติขอสิทธิ์ในการดำเนินการ
โมเดล ToolSpace
แอปต้องเข้าใจพื้นผิว tool โดยไม่ต้องนำเข้า internals ของ Plugin
const tools = await run.toolSpace();
for (const tool of tools.list()) {
console.log(tool.name, tool.source, tool.requiresApproval);
}
SDK ควรเปิดเผย:
- metadata ของ tool ที่ถูกทำให้เป็นรูปแบบมาตรฐาน
- แหล่งที่มา: OpenClaw, MCP, Plugin, channel, runtime หรือ app
- สรุป schema
- policy การอนุมัติ
- ความเข้ากันได้กับ runtime
- tool ถูกซ่อน เป็น readonly สามารถเขียนได้ หรือสามารถทำงานฝั่งโฮสต์ได้หรือไม่
การเรียก tool ผ่าน SDK ควรชัดเจนและมีขอบเขต แอปส่วนใหญ่ควรรันเอเจนต์ ไม่ใช่เรียก tool ใดๆ โดยตรงตามใจ
โมเดล Artifact
Artifact ควรครอบคลุมมากกว่าไฟล์
type ArtifactSummary = {
id: string;
runId?: string;
sessionId?: string;
type:
| "file"
| "patch"
| "diff"
| "log"
| "media"
| "screenshot"
| "trajectory"
| "pull_request"
| "workspace";
title?: string;
mimeType?: string;
sizeBytes?: number;
createdAt: string;
expiresAt?: string;
};
ตัวอย่างทั่วไป:
- การแก้ไขไฟล์และไฟล์ที่สร้างขึ้น
- ชุด patch
- diff ของ VCS
- screenshot และผลลัพธ์สื่อ
- log และชุด trace
- ลิงก์ pull request
- trajectory ของ runtime
- snapshot ของ workspace ใน environment ที่จัดการ
การเข้าถึง artifact ควรรองรับการปกปิดข้อมูล การเก็บรักษา และ URL ดาวน์โหลด โดยไม่ ถือว่า artifact ทุกชิ้นเป็นไฟล์ local ปกติ
โมเดลความปลอดภัย
SDK แอปต้องระบุอำนาจอย่างชัดเจน
scope token ที่แนะนำ:
| Scope | อนุญาตให้ |
|---|---|
agent.read |
แสดงรายการและตรวจสอบเอเจนต์ |
agent.run |
เริ่มการรัน |
session.read |
อ่าน metadata และข้อความของเซสชัน |
session.write |
สร้าง ส่งไปยัง fork compact และ abort เซสชัน |
task.read |
อ่านสถานะงานพื้นหลัง |
task.write |
ยกเลิกหรือแก้ไข policy การแจ้งเตือนของงาน |
approval.respond |
อนุมัติหรือปฏิเสธคำขอ |
tools.invoke |
เรียก tool ที่เปิดเผยโดยตรง |
artifacts.read |
แสดงรายการและดาวน์โหลด artifact |
environment.write |
สร้างหรือทำลาย environment ที่จัดการ |
admin |
การดำเนินการด้านผู้ดูแลระบบ |
ค่าเริ่มต้น:
- ไม่มีการส่งต่อ secret โดยค่าเริ่มต้น
- ไม่มีการส่งผ่านตัวแปร environment แบบไม่จำกัด
- ใช้การอ้างอิง secret แทนค่า secret
- policy sandbox และ network ที่ชัดเจน
- การเก็บรักษา remote environment ที่ชัดเจน
- ต้องมีการอนุมัติสำหรับการทำงานบนโฮสต์ เว้นแต่ policy จะพิสูจน์เป็นอย่างอื่น
- event ดิบของ runtime ถูกปกปิดข้อมูลก่อนออกจาก Gateway เว้นแต่ผู้เรียกจะมี scope การวินิจฉัยที่เข้มกว่า
ผู้ให้บริการ managed environment
เอเจนต์ที่จัดการควรใช้เป็นผู้ให้บริการ environment
type EnvironmentProvider = {
id: string;
capabilities: {
checkout?: boolean;
sandbox?: boolean;
networkPolicy?: boolean;
secrets?: boolean;
artifacts?: boolean;
logs?: boolean;
pullRequests?: boolean;
longRunning?: boolean;
};
};
การใช้งานครั้งแรกไม่จำเป็นต้องเป็น SaaS แบบโฮสต์ สามารถกำหนดเป้าหมายไปยัง โฮสต์ node ที่มีอยู่, workspace ชั่วคราว, runner แบบ CI หรือ environment แบบ Testbox ได้ สัญญาที่สำคัญคือ:
- เตรียม workspace
- ผูก environment และ secret อย่างปลอดภัย
- เริ่มการรัน
- สตรีม event
- รวบรวม artifact
- ล้างข้อมูลหรือเก็บรักษาตาม policy
เมื่อสิ่งนี้เสถียรแล้ว บริการคลาวด์แบบโฮสต์สามารถใช้สัญญาผู้ให้บริการเดียวกันได้
โครงสร้างแพ็กเกจ
แพ็กเกจที่แนะนำ:
| Package | วัตถุประสงค์ |
|---|---|
@openclaw/sdk |
SDK ระดับสูงสาธารณะและไคลเอนต์ Gateway ระดับต่ำที่สร้างขึ้นอัตโนมัติ |
@openclaw/sdk-react |
React hooks เสริมสำหรับแดชบอร์ดและผู้สร้างแอป |
@openclaw/sdk-testing |
ตัวช่วยทดสอบและเซิร์ฟเวอร์ Gateway ปลอมสำหรับการเชื่อมต่อแอป |
repo มี openclaw/plugin-sdk/* สำหรับ Plugin อยู่แล้ว รักษา namespace นั้น
ให้แยกจากกันเพื่อหลีกเลี่ยงการทำให้ผู้เขียน Plugin สับสนกับนักพัฒนาแอป
กลยุทธ์ไคลเอนต์ที่สร้างขึ้นอัตโนมัติ
ไคลเอนต์ระดับต่ำควรสร้างจาก schema โปรโตคอล Gateway ที่มีเวอร์ชัน แล้วครอบด้วยคลาสที่เขียนด้วยมือและใช้งานสะดวก
การจัดชั้น:
- แหล่งความจริงของสคีมา Gateway.
- ไคลเอนต์ TypeScript ระดับต่ำที่สร้างขึ้น.
- ตัวตรวจสอบความถูกต้องขณะรันไทม์สำหรับอินพุตภายนอกและเพย์โหลดของเหตุการณ์.
- wrapper ระดับสูง
OpenClaw,Agent,Session,Run,Task, และArtifact. - ตัวอย่าง Cookbook และการทดสอบการผสานรวม.
ประโยชน์:
- มองเห็นการเบี่ยงเบนของโปรโตคอลได้
- การทดสอบสามารถเปรียบเทียบเมธอดที่สร้างขึ้นกับ export ของ Gateway ได้
- App SDK เป็นอิสระจากส่วนภายในของ Plugin SDK
- ผู้ใช้ระดับต่ำยังคงเข้าถึงโปรโตคอลได้ครบถ้วน
- ผู้ใช้ระดับสูงได้รับ API ผลิตภัณฑ์ขนาดเล็ก