Get started
การอนุมัติของผู้ดำเนินการบนหลายอินเทอร์เฟซ
การอนุมัติของผู้ดำเนินการจากหลายพื้นผิว
การออกแบบนี้ติดตาม #103505 โดยแทนที่อำนาจการอนุมัติภายในโปรเซสด้วยวงจรชีวิตเดียวที่ Gateway เป็นเจ้าของและมี SQLite รองรับ การอนุมัติ exec หรือ Plugin/เครื่องมือทุกครั้งที่ Gateway เป็นเจ้าของจะได้รับ ID ที่คงที่หนึ่งรายการ เส้นทาง Control UI ที่ผ่านการตรวจสอบสิทธิ์หนึ่งเส้นทาง การตัดสินผลแบบอะตอมมิกที่คำตอบแรกเป็นผู้ชนะ และการฉายข้อมูลสำหรับผู้ดำเนินการเท่านั้นไปยังสตรีมของเซสชันต้นทางและเซสชันบรรพบุรุษ
การดำเนินการแบบอินไลน์และลิงก์เชิงลึกใช้งานร่วมกันได้ ไม่มีสวิตช์สลับโหมดการอนุมัติ
เป้าหมาย
- ออบเจ็กต์การอนุมัติถาวรหนึ่งรายการสำหรับด่าน exec และ Plugin/เครื่องมือ
- เส้นทาง
${controlUiBasePath}/approve/{approvalId}ที่คงที่ - ตัดสินผลจาก Control UI, แอปแบบเนทีฟ หรือพื้นผิวช่องทางใดก็ตามที่ได้รับอนุญาต
- พฤติกรรมแบบอะตอมมิกที่คำตอบแรกเป็นผู้ชนะในพื้นผิวที่ทำงานพร้อมกัน
- การลองซ้ำด้วยคำตอบเดียวกันเป็นแบบ idempotent ส่วนคำตอบที่ขัดแย้งและมาภายหลังไม่สามารถเขียนทับคำตอบที่ชนะได้
- การหมดเวลา คำตัดสินที่เชื่อถือได้แต่มีรูปแบบไม่ถูกต้อง เส้นทางที่ขาดหาย การยกเลิก และการเริ่มใหม่ต้องปฏิเสธโดยค่าเริ่มต้น
- เหตุการณ์ร้องขอและเหตุการณ์ปลายทางต้องไปถึงเซสชันต้นทางและเจ้าของระดับพาเรนต์/ตัวประสานงานที่เกี่ยวข้องทั้งหมด
- ช่องทางได้รับการดำเนินการสำหรับการอนุมัติและการนำทางที่มีชนิดข้อมูล ส่วนข้อมูลคอลแบ็กของทรานสปอร์ตยังคงเป็นข้อมูลเฉพาะภายในช่องทาง
- เมธอด exec/Plugin ของ Gateway ที่มีอยู่ยังคงเข้ากันได้ ขณะที่การนำไปใช้งานของเมธอดเหล่านั้นรวมเข้าสู่บริการเดียว
สิ่งที่ไม่ใช่เป้าหมาย
- การคงอยู่หรือดำเนินการเครื่องมือที่ถูกบล็อกต่อหลังจาก Gateway เริ่มใหม่
- การทำให้ ID หรือ URL การอนุมัติเป็นข้อมูลรับรองแบบ bearer
- การเพิ่มพรอมต์การอนุมัติลงในทรานสคริปต์ที่โมเดลมองเห็น หรือปลุกเอเจนต์พาเรนต์
- การย้ายนโยบายการอนุมัติ คำสั่งผลิตภัณฑ์ หรือการอนุญาตผู้ตรวจสอบไปยัง Plugin ช่องทาง
- การโคลนสถานะการอนุมัติแยกตามช่องทาง อุปกรณ์ หรือบรรพบุรุษ
- การออกแบบรายการอนุญาต exec การประกอบนโยบาย Plugin หรือการคงอยู่ของ
allow-alwaysใหม่ ยกเว้นในส่วนที่จำเป็นเพื่อทำให้ผลลัพธ์ปลายทางไม่กำกวม - การทำให้ TUI แบบฝังที่ไม่มี Gateway เข้าถึงได้จากระยะไกลในระยะแรก โดยยังคงใช้งานได้เฉพาะภายในเครื่องและต้องปฏิเสธโดยค่าเริ่มต้นเมื่อไม่มีผู้ตรวจสอบ
ค่าพื้นฐานก่อนเปิดตัวและแผนผังหลักฐาน
ตารางนี้บันทึกสถานะการนำไปใช้งานเมื่อเปิด #103505 ส่วนการเปิดตัวด้านล่างติดตามรีจิสทรีถาวร การดำเนินการที่มีชนิดข้อมูล หน้าเว็บลิงก์เชิงลึก และส่วนเพิ่มของไคลเอนต์แบบเนทีฟที่สร้างต่อยอดจากค่าพื้นฐานดังกล่าว
| พื้นผิว | จุดเริ่มต้นและเจ้าของตามค่าพื้นฐาน | พฤติกรรมและช่องว่างตามค่าพื้นฐาน |
|---|---|---|
| exec ของเอเจนต์ | src/agents/bash-tools.exec-approval-request.ts, src/agents/bash-tools.exec-host-shared.ts |
การลงทะเบียน exec.approval.* แบบสองระยะช่วยป้องกันภาวะแข่งขันของ /approve ที่เกิดก่อนเวลา แต่การหมดเวลายังอาจกลายเป็นการอนุญาตผ่าน askFallback ได้ |
| ด่านเครื่องมือของ Plugin | src/agents/agent-tools.before-tool-call.ts |
ร้องขอ plugin.approval.*; timeoutBehavior: "allow" สามารถอนุมัติด่านที่หมดเวลาแล้วได้ โหมดฝังมีอำนาจภายในโปรเซสแยกต่างหากใน src/infra/embedded-plugin-approval-broker.ts |
| ด่าน Node ของ Plugin | src/gateway/node-invoke-plugin-policy.ts |
สร้างและกระจายโดยตรงผ่านตัวจัดการ Plugin ทำให้เกิดการทำซ้ำบางส่วนของวงจรชีวิตเมธอดเซิร์ฟเวอร์ |
| อำนาจของ Gateway | src/gateway/server-aux-handlers.ts, src/gateway/exec-approval-manager.ts, src/gateway/server-methods/approval-shared.ts |
ตัวจัดการ exec และ Plugin แยกกันใช้แมปภายในโปรเซส รายการปลายทางคงอยู่เป็นเวลา 15 วินาที หลักคำตอบแรกเป็นผู้ชนะมีผลเฉพาะภายในโปรเซสเดียว |
| โปรโตคอล Gateway | packages/gateway-protocol/src/schema/exec-approvals.ts, packages/gateway-protocol/src/schema/plugin-approvals.ts, src/gateway/methods/core-descriptors.ts |
exec มี get สำหรับรายการที่รอดำเนินการเท่านั้น ส่วน Plugin ไม่มี get และไม่มีการค้นหาปลายทางที่ไม่ขึ้นกับชนิดสำหรับลิงก์เชิงลึก |
| การส่งมอบ | src/infra/exec-approval-channel-runtime.ts, src/infra/approval-native-runtime.ts, src/infra/approval-handler-runtime.ts |
รองรับการกำหนดเส้นทางไปยังต้นทาง DM ของผู้อนุมัติ การเล่นซ้ำรายการที่รอดำเนินการ ตัวจัดการแบบเนทีฟ และการล้างข้อมูลปลายทางภายในโปรเซส ส่วนงานติดตามผลแยกต่างหากจะเพิ่มการกระทบยอดปลายทางแบบถาวร |
| การดำเนินการแบบพกพา | src/interactive/payload.ts, src/plugin-sdk/interactive-runtime.ts, src/plugin-sdk/approval-reply-runtime.ts |
ปุ่มอนุมัติเป็นการดำเนินการคำสั่งที่มี /approve ... ส่วนเป้าหมาย URL และ Web App เป็นฟิลด์ปุ่มที่ไม่มีชนิดข้อมูล |
| Telegram | extensions/telegram/src/approval-handler.runtime.ts, extensions/telegram/src/button-types.ts |
ตัวเรนเดอร์แยกวิเคราะห์ข้อความคำสั่งเพื่อระบุความหมายเชิงการอนุมัติก่อนสร้างข้อมูลคอลแบ็กส่วนตัว |
| Control UI | ui/src/app/exec-approval.ts, ui/src/app/overlays.ts, ui/src/components/exec-approval.ts |
UI การอนุมัติเป็นโมดัลส่วนกลาง ui/src/app-route-paths.ts และ ui/src/app-routes.ts ใช้เส้นทางแบบตรงตัวและเขียนเส้นทางที่ไม่รู้จักใหม่ให้ไปยัง Chat |
| ความเป็นเจ้าของเซสชัน | src/agents/subagent-registry.types.ts, src/agents/subagent-registry-read.ts, src/config/sessions/types.ts |
มีความเป็นเจ้าของโดยคอนโทรลเลอร์ ผู้ร้องขอ พาเรนต์ที่ระบุอย่างชัดเจน และการสร้างแบบเดิมอยู่แล้ว แต่เหตุการณ์การอนุมัติยังไม่ได้ฉายไปยังสตรีมของเซสชันเหล่านั้น |
| สถานะที่ใช้ร่วมกัน | src/state/openclaw-state-schema.sql, src/state/openclaw-state-db.ts |
ธุรกรรมแบบทันทีและการอัปเดตตามเงื่อนไขของ Kysely ที่มีอยู่รองรับการเปรียบเทียบและตั้งค่าแบบถาวรใน state/openclaw.sqlite |
การทดสอบปัจจุบันที่เป็นตัวแทนประกอบด้วย src/gateway/exec-approval-manager.test.ts, src/gateway/server-methods/approval-shared.test.ts, src/agents/bash-tools.exec-gateway-approval.e2e.test.ts, extensions/telegram/src/approval-handler.runtime.test.ts และ ui/src/e2e/approval-flow.e2e.test.ts
SDK ของ Plugin ยังคงเป็นขอบเขตเดียวระหว่างช่องทาง/Plugin การเปลี่ยนแปลงรันไทม์และการนำเสนอการอนุมัติต้องส่งออกผ่านพาธย่อย src/plugin-sdk/approval-*.ts และ src/plugin-sdk/interactive-runtime.ts ที่มีอยู่ โค้ดใช้งานจริงของ Plugin ต้องไม่นำเข้าส่วนภายในของ Gateway
งานที่มีมาก่อน
Omnigent มี UX และความหมายของความล้มเหลวที่เป็นประโยชน์:
approval.pyพัก ASK ไว้ ใช้การหมดเวลาตามแต่ละนโยบาย และถือว่าเฉพาะการยอมรับที่ตรงกันเท่านั้นเป็นการอนุมัติsessions.pyมีด่านชุดทดสอบแบบเนทีฟฝั่งเซิร์ฟเวอร์และการฉายคำขอ/การตัดสินผลไปยังบรรพบุรุษApprovePage.tsxมีหน้าการอนุมัติบนอุปกรณ์เคลื่อนที่แบบสแตนด์อโลน
อย่าคัดลอกคำกล่าวอ้างเรื่องพื้นที่จัดเก็บของระบบดังกล่าวโดยไม่พิจารณาอย่างรอบคอบ สถานะที่รอดำเนินการและใช้งานอยู่ในปัจจุบันเป็นข้อมูลภายในโปรเซสใน _elicitation_registry.py และตารางรายการที่รอดำเนินการซึ่งไม่ได้ใช้ถูกลบโดย e3b1f2a4c9d7_drop_pending_tool_calls_table.py OpenClaw จงใจดำเนินการให้ไกลกว่านั้น โดยให้ SQLite เป็นแหล่งข้อมูลที่มีอำนาจ และทุกการเปลี่ยนผ่านไปยังสถานะปลายทางเป็นการเปรียบเทียบและตั้งค่าฐานข้อมูล
สถาปัตยกรรมและความเป็นเจ้าของ
Gateway เป็นเจ้าของวงจรชีวิต:
- เอเจนต์ ฮุกของ Plugin หรือนโยบาย Node จัดเตรียมคำขอเฉพาะชนิดและการผูกการดำเนินการภายในโปรเซส
- Gateway ตรวจสอบคำขอและสร้างการฉายข้อมูลสำหรับผู้ตรวจสอบที่ผ่านการกรอง
- บริการการอนุมัติคำนวณกลุ่มผู้รับที่เป็นต้นทาง/เจ้าของ แทรกแถวข้อมูลหลัก แล้วลงทะเบียนตัวรอภายในโปรเซส
- หลังจากแทรกข้อมูลถาวรแล้ว Gateway จะเผยแพร่เหตุการณ์การอนุมัติที่มีอยู่ การฉายข้อมูลเซสชัน การแจ้งเตือนช่องทาง และการพุชแบบเนทีฟ
- ทุกพื้นผิวตัดสินผลผ่านบริการเดียวกัน
- บริการคอมมิตการเปลี่ยนผ่านปลายทางหนึ่งครั้ง ปลุกตัวรอของรันไทม์ และเผยแพร่การฉายข้อมูลปลายทาง
- การส่งเหตุการณ์ที่ล้มเหลวจะไม่ย้อนกลับการตัดสินใจที่คอมมิตแล้ว ไคลเอนต์กู้คืนผ่าน
approval.getหรือการเล่นซ้ำรายการ
ขอบเขตความเป็นเจ้าของ:
src/gateway/: บริการการอนุมัติ การตรวจสอบสิทธิ์ อะแดปเตอร์ RPC การสร้าง URL วงจรชีวิตตัวรอ และการเผยแพร่เหตุการณ์src/state/: สคีมาที่ใช้ร่วมกันและชนิดข้อมูล Kysely ที่สร้างขึ้นsrc/infra/: โมเดลมุมมองการอนุมัติที่ผ่านการกรองและการสร้างการนำเสนอแบบพกพาsrc/agents/: ร้องขอ รอ และใช้คำตัดสินที่ส่งกลับมา โดยไม่คงข้อมูลsrc/channels/และextensions/*: เรนเดอร์การดำเนินการที่มีชนิดข้อมูล ตรวจสอบสิทธิ์ผู้ใช้ช่องทาง เข้ารหัสคอลแบ็กส่วนตัว และอัปเดตตัวควบคุมที่ส่งมอบแล้วsrc/plugin-sdk/: เฉพาะสัญญาการอนุมัติและการนำเสนอสาธารณะui/: หน้าแบบสแตนด์อโลนและไคลเอนต์คิว/โมดัลที่มีอยู่
ตัวรอภายในโปรเซสเป็นกลไกการแจ้งเตือน ไม่ใช่ผู้มีอำนาจ การลงทะเบียนจะแทรกแถวและติดตั้งตัวรอแบบซิงโครนัสก่อนเผยแพร่คำขอ เพื่อไม่ให้ตัวตัดสินผลเข้ามาแทรกระหว่างสองขั้นตอนดังกล่าว ตัวตัดสินผลทั้งหมดในภายหลังจะคอมมิตผ่าน SQLite ก่อนตัดสินตัวรอนั้น
ระเบียนถาวร
เพิ่มตาราง operator_approvals หนึ่งตารางลงในฐานข้อมูลสถานะที่ใช้ร่วมกัน
| คอลัมน์ | วัตถุประสงค์ |
|---|---|
approval_id |
ID มาตรฐานที่ไม่ซ้ำกันทั่วทั้งระบบ คง exec ID และ ID ของ plugin: ที่มีอยู่ไว้เพื่อความเข้ากันได้ของโปรโตคอล แต่อย่าอนุมานชนิดจากคำนำหน้า |
resolution_ref |
ตัวระบุตำแหน่ง SHA-256 แบบเต็มในรูปแบบ base64url ที่ไม่ซ้ำกัน สำหรับ callback ของการขนส่งที่ไม่สามารถส่ง ID มาตรฐานได้ ไม่ใช่การให้สิทธิ์หรือ ID ของ URL สาธารณะ |
kind |
ตัวจำแนก exec | plugin แบบปิด |
status |
สถานะ pending | allowed | denied | expired | cancelled แบบปิด |
presentation_json |
โปรเจกชันสำหรับผู้ตรวจสอบที่ผ่านการตรวจสอบและติดแท็กชนิด คำขอรันไทม์ดิบ การผูกคำสั่ง และเพย์โหลด callback ยังคงอยู่ภายในโปรเซส |
source_agent_id, source_session_key |
จุดยึดสำหรับโปรเจกชันข้อมูลประจำตัวต้นทางและเซสชัน คีย์เซสชันมีความคงทนถาวร แต่ UUID เซสชันที่หมุนเวียนไม่มีความคงทน |
audience_session_keys_json |
อาร์เรย์ JSON ที่เรียงลำดับและตัดรายการซ้ำ ซึ่งสร้างจากการเดินตรวจสอบความเป็นเจ้าของแบบกว้างก่อนที่มีขอบเขต เหตุการณ์ที่ร้องขอและเหตุการณ์ปลายทางใช้สแนปช็อตเดียวกันนี้ |
requested_by_device_id, requested_by_client_id |
เมทาดาทาของผู้ร้องขอ/การตรวจสอบที่คงทนถาวร ID การเชื่อมต่อจะอยู่ในหน่วยความจำและไม่ใช่ตัวการหลักข้ามพื้นผิว |
reviewer_device_ids_json |
อุปกรณ์ผู้ตรวจสอบเป้าหมายที่ระบุอย่างชัดเจนซึ่งเป็นทางเลือก และจัดหาโดยรันไทม์การอนุมัติที่เชื่อถือได้เท่านั้น |
runtime_epoch |
ยุคของโปรเซสที่เป็นเจ้าของการดำเนินการซึ่งถูกพักไว้ ใช้ยกเลิกแถวที่ไม่มีเจ้าของหลังจากรีสตาร์ต |
created_at_ms, expires_at_ms, updated_at_ms |
การกำหนดเวลาที่เป็นแหล่งข้อมูลหลัก |
decision |
การตัดสินใจของผู้ใช้อย่างชัดเจนเมื่อมีอยู่ |
terminal_reason |
เหตุผลแบบปิด เช่น user, timeout, malformed-verdict, no-route, run-aborted หรือ gateway-restart |
resolved_at_ms, resolver_kind, resolver_id |
ข้อมูลประจำตัวของผู้ชนะและการตรวจสอบที่เก็บไว้ฝั่งเซิร์ฟเวอร์ โปรเจกชันสำหรับผู้ตรวจสอบจะละเว้นตัวระบุผู้แก้ไขปัญหาแบบดิบ |
consumed_at_ms, consumed_by |
ตัวป้องกันการเล่นซ้ำแยกต่างหากสำหรับ allow-once การใช้งานต้องไม่ลบการตัดสินใจที่บันทึกไว้ |
ดัชนีที่จำเป็น:
| ดัชนี | วัตถุประสงค์ |
|---|---|
unique (resolution_ref) |
ปฏิเสธความกำกวมข้ามคอลัมน์ของ approval_id/resolution_ref ระหว่างการแทรก |
(status, expires_at_ms) |
ค้นหาการอนุมัติที่รอดำเนินการและปรับกำหนดเวลาที่เป็นแหล่งข้อมูลหลักให้สอดคล้องกัน |
(source_session_key, created_at_ms DESC) |
เล่นซ้ำการอนุมัติล่าสุดสำหรับเซสชันต้นทางหนึ่งเซสชัน |
(resolved_at_ms) |
ล้างการอนุมัติปลายทางที่เก็บไว้ตามนโยบายการเก็บรักษาแบบคงที่ |
อาร์เรย์กลุ่มเป้าหมายมีขนาดเล็กและมีขอบเขต การเล่นซ้ำที่กรองตามเซสชันจะเลือกแถวที่รอดำเนินการซึ่งมองเห็นได้ผ่าน Kysely ก่อน จากนั้นจึงถอดรหัสและกรองอาร์เรย์กลุ่มเป้าหมายที่มีขอบเขตในโค้ดแอปพลิเคชัน โดยไม่ใช้การจับคู่สตริงหรือคิวรี JSON ด้วย SQL ดิบ
เก็บแถวปลายทางไว้เป็นเวลา 30 วัน ให้สอดคล้องกับการเก็บรักษาเมทาดาทาการตรวจสอบใน src/audit/audit-event-store.ts การล้างข้อมูลเป็นนโยบายการบำรุงรักษาแบบคงที่ ไม่ใช่พื้นผิวการกำหนดค่าใหม่ ฐานข้อมูลเป็นสถานะระนาบควบคุมภายในเครื่องแบบส่วนตัว แต่ API สำหรับผู้ตรวจสอบต้องไม่เปิดเผยคำขอที่จัดเก็บไว้ทั้งหมดหรือการผูกรันไทม์
เครื่องสถานะและการเปรียบเทียบแล้วกำหนดค่า
เฉพาะการเปลี่ยนสถานะต่อไปนี้เท่านั้นที่ถูกต้อง:
pending -> allowed:allow-onceหรือallow-alwaysที่ระบุอย่างชัดเจนpending -> denied: การปฏิเสธที่ระบุอย่างชัดเจน คำตัดสินปลายทางที่ผิดรูปแบบจากแหล่งที่เชื่อถือได้ หรือไม่มีเส้นทางส่งpending -> expired: ถึงกำหนดเวลาที่เป็นแหล่งข้อมูลหลักpending -> cancelled: การยกเลิกการรัน การปิดระบบอย่างราบรื่น หรือการกู้คืนรายการไร้เจ้าของหลังรีสตาร์ต
สถานะปลายทางทุกสถานะที่ไม่ได้รับอนุญาตมีคำตัดสินที่มีผลเป็นปฏิเสธ
การแก้ไขใช้ธุรกรรม SQLite แบบทันทีหนึ่งรายการ และการอัปเดตตามเงื่อนไขของ Kysely ที่เทียบเท่ากับ:
UPDATE operator_approvalsSET status = ?, decision = ?, terminal_reason = ?, resolved_at_ms = ?WHERE approval_id = ? AND status = 'pending' AND expires_at_ms > ?;หากการอัปเดตไม่ส่งผลต่อแถวใด ธุรกรรมเดียวกันจะอ่านระเบียน:
- ไม่พบหรือไม่ได้รับอนุญาต: ส่งคืนว่าไม่พบ และอย่าเปิดเผยว่ามีอยู่
- ยังรอดำเนินการแต่ถึงกำหนดเวลาแล้ว: เปรียบเทียบแล้วกำหนดค่าเป็น
expiredจากนั้นส่งคืนแถวปลายทางนั้น - เป็นการตัดสินใจเดียวกับที่บันทึกไว้: ส่งคืนความสำเร็จแบบทำซ้ำได้โดยให้ผลเดิมพร้อมผู้ชนะที่บันทึกไว้
- เป็นการตัดสินใจที่ต่างกัน: API แบบรวมส่งคืน
applied: falseพร้อมผู้ชนะที่บันทึกไว้ ส่วนอะแดปเตอร์แบบเดิมจะคงAPPROVAL_ALREADY_RESOLVEDไว้ในกรณีที่สัญญาที่เผยแพร่แล้วกำหนด - สถานะปลายทางใดๆ: ห้ามแก้ไขโดยเด็ดขาด
now == expires_at_ms หมดอายุแล้ว เวลาของ Gateway เป็นแหล่งข้อมูลหลัก
การดำเนินการ allow-once ใช้ CAS ครั้งที่สองกับ consumed_at_ms IS NULL โดยผูกกับบริบทคำสั่ง/การรันระบบเดิมที่ตรงกันทุกประการ แถวการอนุมัติยังคงเป็นระเบียนการตรวจสอบหลังการใช้งาน
อินพุต HTTP/RPC ที่ผิดรูปแบบซึ่งไม่สามารถยืนยันตัวตนหรือระบุการอนุมัติได้จะถูกปฏิเสธโดยไม่มีการแก้ไข และไม่สามารถอนุมัติได้โดยเด็ดขาด คำตัดสินปลายทางที่ผิดรูปแบบซึ่งได้รับจากฮาร์เนส/ตัวรอที่เชื่อถือได้สำหรับการอนุมัติที่ทราบ จะเปลี่ยนสถานะเป็น denied
API ของ Gateway
เพิ่มเมธอดสำหรับผู้ตรวจสอบที่ไม่ขึ้นกับชนิด:
| เมธอด | สัญญา |
|---|---|
approval.get { id } |
ส่งคืนโปรเจกชันที่มองเห็นได้ซึ่งอยู่ระหว่างรอดำเนินการหรือเป็นปลายทางที่เก็บรักษาไว้ |
approval.resolve { id, kind, decision } |
รับ ID มาตรฐานหรือตัวอ้างอิงการขนส่งขนาดคงที่ จากนั้นดำเนินการตรวจสอบสิทธิ์ ตรวจสอบชนิดและการตัดสินใจที่อนุญาต ปรับกำหนดเวลาให้สอดคล้อง และทำ CAS ปลายทาง การตอบกลับจะมี ID มาตรฐานเสมอ |
หลังจาก CAS สำเร็จ ให้ส่งคืนโปรเจกชันที่คอมมิตแล้วทันที เหตุการณ์แบบเดิม ตัวส่งต่อของช่องทาง และตัวทำให้ push เป็นปลายทาง เป็นการดำเนินการติดตามผลแบบพยายามให้ดีที่สุด พื้นผิวที่ช้าหรือล้มเหลวต้องไม่ทำให้การตอบกลับที่ชนะล่าช้าหรือย้อนกลับ
การตรวจสอบคำขอเฉพาะชนิดยังคงอยู่ใน exec.approval.request และ plugin.approval.request ส่วน exec.approval.get/list/waitDecision/resolve และ plugin.approval.list/waitDecision/resolve ที่มีอยู่จะกลายเป็นอะแดปเตอร์ขอบเขตโปรโตคอลไปยังบริการมาตรฐาน เนื่องจากเป็น API ของ Gateway ที่เผยแพร่แล้ว ผู้เรียกใช้ภายในจะย้ายไปยังบริการในการเปลี่ยนแปลงเดียวกัน
โปรเจกชันสำหรับผู้ตรวจสอบเป็น tagged union:
type OperatorApproval = { id: string; status: OperatorApprovalStatus; presentation: | { kind: "exec"; commandText: string /* ตัวอย่าง exec ที่ปลอดภัย */ } | { kind: "plugin"; title: string; description: string /* ตัวอย่าง Plugin ที่ปลอดภัย */ }; // ฟิลด์วงจรชีวิตส่วนกลาง};พาธที่เสถียรถูกสร้างขึ้น ไม่ได้จัดเก็บถาวร approval.get ส่งคืน urlPath พื้นผิวที่ทราบต้นทางสาธารณะที่ได้รับอนุมัติอาจได้รับ url แบบสัมบูรณ์ด้วย สแนปช็อตสำหรับผู้ตรวจสอบจะละเว้นคีย์เซสชันของต้นทางและกลุ่มเป้าหมาย Gateway เก็บคีย์การกำหนดเส้นทางเหล่านั้นไว้ฝั่งเซิร์ฟเวอร์สำหรับโปรเจกชัน session.approval ที่แยกต่างหาก
เหตุการณ์และการดำเนินการแบบพกพา
PR 1 คงชื่อเหตุการณ์ เพย์โหลด และตัวกรองผู้รับระดับระเบียนที่เผยแพร่แล้วไว้:
exec.approval.requestedexec.approval.resolvedplugin.approval.requestedplugin.approval.resolved
เหตุการณ์แบบเดิมเหล่านั้นอาจมีคำขอรันไทม์ทั้งหมด ดังนั้นจึงต้องไม่กระจายไปยังไคลเอนต์ทุกตัวที่อยู่ในขอบเขตการอนุมัติ PR 5 เพิ่มฟิลด์วงจรชีวิตที่มีแท็ก (status, sourceSessionKey, urlPath, เมทาดาทาปลายทาง และ kind ระดับการนำเสนอ) ผ่านโปรเจกชันวงจรชีวิตที่ผ่านการปรับให้ปลอดภัย แทนการขยายการส่งเหตุการณ์แบบเดิม
เพิ่มเหตุการณ์โปรเจกชัน session.approval ที่อยู่ในขอบเขตการอนุมัติ เผยแพร่เหตุการณ์มาตรฐานหนึ่งครั้งพร้อมคีย์กลุ่มเป้าหมายที่จัดเก็บถาวร โดยผู้สมัครรับข้อมูลของเซสชันที่ตรงกันทุกประการจะได้รับเหตุการณ์เดียวกันสำหรับแต่ละคีย์ที่ตรงกัน:
sessionKey: สตรีมที่รับโปรเจกชันsourceSessionKey: ลูก/ต้นทางที่ทำให้เกิดเกตphase:pending \| terminalซึ่งจำแนกตามสถานะการอนุมัติ- โปรเจกชัน
OperatorApprovalที่ปลอดภัยหนึ่งรายการ
ไคลเอนต์เลือกเข้าร่วมด้วย sessions.messages.subscribe { key, agentId?, includeApprovals: true } การตอบกลับที่สำเร็จจะเพิ่ม approvalReplay ซึ่งมีการอนุมัติที่รอดำเนินการในปัจจุบันได้สูงสุด 1,000 รายการ สำหรับคีย์สตรีมที่ตรงกันทุกประการและไคลเอนต์ที่สมัครรับข้อมูลได้รับอนุญาตระดับระเบียนให้ตรวจสอบด้วย truncated: false ทำให้การเล่นซ้ำที่กรองแล้วเป็นแหล่งข้อมูลหลัก และไคลเอนต์ที่เชื่อมต่อใหม่จะแทนที่ชุดรายการที่รอดำเนินการในเครื่องด้วยข้อมูลนั้น ส่วน truncated: true เป็นสัญญาณโอเวอร์โหลด และไคลเอนต์ต้องเก็บรายการในเครื่องที่ยังไม่เห็นไว้จนกว่าการค้นหาแบบมาตรฐานหรือเหตุการณ์วงจรชีวิตในภายหลังจะยุติสถานะรายการเหล่านั้น การหมดเวลาแบบคงทนที่พบภายหลังระหว่างการเล่นซ้ำจะส่ง tombstone ปลายทางเฉพาะไปยังกลุ่มเป้าหมายที่สมัครรับข้อมูลและได้รับอนุญาตระดับระเบียน ก่อนส่งคืนสแนปช็อตใหม่ operator.admin อาจเลือกเข้าร่วมโดยตรง ส่วนไคลเอนต์ที่มีขอบเขตแคบกว่าต้องมีทั้งข้อมูลประจำตัวอุปกรณ์ที่จับคู่แล้วและ operator.approvals การสมัครรับข้อมูลเซสชันเพียงอย่างเดียวไม่เคยมอบสิทธิ์มองเห็นการอนุมัติ
ลงทะเบียนเหตุการณ์ภายใต้ operator.approvals ใน src/gateway/server-broadcast.ts โปรเจกชันนี้ใช้เพื่อการสังเกตการณ์ โดยจะไม่เพิ่มแถวทรานสคริปต์ ส่ง sessions.changed หรือปลุกเอเจนต์
ขยาย MessagePresentationAction ใน src/interactive/payload.ts:
type MessagePresentationAction = | { type: "command"; command: string } | { type: "callback"; value: string } | { type: "approval"; approvalId: string; approvalKind: "exec" | "plugin"; decision: ExecApprovalDecision; } | { type: "url"; url: string } | { type: "web-app"; url: string };Core สร้างการดำเนินการตัดสินใจแบบมีชนิดและลิงก์ตรวจสอบแยกต่างหากเมื่อมีต้นทาง Control UI แบบสัมบูรณ์ที่ได้รับอนุมัติ ช่องทางต่าง ๆ เข้ารหัสการดำเนินการอนุมัติเป็นรูปแบบ callback ของตนเองและส่งผลการตัดสินไปยังบริการมาตรฐาน callback จะใช้ ID มาตรฐานที่ตรงกันทุกประการเมื่อมีขนาดพอดี มิฉะนั้นจะใช้ resolution_ref แบบไดเจสต์เต็มที่ไม่ซ้ำกันของแถว การอ้างอิงเป็นเพียงคีย์ค้นหาแบบย่อเท่านั้น โดยยังคงต้องใช้การยืนยันตัวตนของ Gateway ตามปกติ การอนุญาตระดับระเบียน ชนิดที่ระบุอย่างชัดเจน การตรวจสอบการตัดสินใจที่อนุญาต การกระทบยอดกำหนดเวลา และ CAS แบบคำตอบแรก ช่องทางต้องไม่ตัดทอน ID แก้ไขคำนำหน้าแฮช แยกวิเคราะห์ข้อความ /approve หรืออนุมานชนิดจากคำนำหน้า ID
เก็บ button.url, button.webApp และตัวควบคุมการอนุมัติที่มีคำสั่งรองรับไว้เป็นอินพุตความเข้ากันได้ของ plugin SDK ที่เลิกใช้แล้ว ปรับให้อยู่ในรูปแบบมาตรฐานที่ขอบเขต SDK และย้ายผู้เรียกใช้ภายในแบบรวมทุกตัวใน PR เดียวกัน /approve {id} {decision} ยังคงเป็นข้อความสำรองและคำสั่ง CLI/แชต ไม่ใช่สัญญาเชิงความหมายของปุ่ม
Control UI
เส้นทางคือ ${basePath}/approve/{approvalId} โดย ID เป็นพารามิเตอร์พาธเพียงรายการเดียว ส่วนข้อมูลระบุตัวตนของเซสชันต้นทางมาจากระเบียน
เนื่องจากเราเตอร์ปัจจุบันมีเส้นทางคงที่ที่ตรงกันทุกประการและเขียนเส้นทางที่ไม่รู้จักใหม่ไปยังแชต ให้ตรวจหาดีปลิงก์นี้ใน ui/src/app/bootstrap.ts ก่อนการปรับเส้นทางให้อยู่ในรูปแบบมาตรฐานตามปกติ ใช้การตั้งค่า Gateway/การยืนยันตัวตนตามปกติซ้ำ แต่แสดงหน้าการอนุมัติแบบสแตนด์อโลนนอกเชลล์แถบด้านข้างและโมดอลส่วนกลาง
เอกสารเป็นของ Gateway ที่ให้บริการ URL นั้น การเชื่อมต่อเริ่มต้นจะไม่สนใจการเลือก Gateway ระยะไกลที่แอปเต็มรูปแบบบันทึกไว้ โดยไม่เปลี่ยนแปลงหรือคัดลอกการตั้งค่าของการเลือกดังกล่าว มีเพียงการยืนยันตัวตนที่ยังคงจำกัดขอบเขตอยู่ในเซสชันของ Gateway ที่ให้บริการ การยืนยันตัวตนแบบเนทีฟที่เชื่อถือได้หรือการแทนที่ gatewayUrl ที่ยืนยันแยกต่างหากอาจเปลี่ยนเป้าหมายได้ Core สงวนเนมสเปซ /approve แบบหนึ่งเซกเมนต์ไว้ก่อนเส้นทาง HTTP ของ plugin และการตรวจหาส่วนขยายแบบคงที่ รวมถึง ID ที่ลงท้ายด้วย .json หรือ .js เมื่อปิดใช้งานการให้บริการ Control UI เส้นทางที่สงวนไว้จะปฏิเสธอย่างปลอดภัยด้วย 404 เก็บหน้าไว้ในบันเดิลหลักของ Control UI เพื่อไม่ให้ lazy chunk ที่ล้มเหลวทำให้การตัดสินใจด้านความปลอดภัยค้างอยู่ที่ตัวหมุนโหลด
สถานะของหน้า:
- กำลังโหลด
- ต้องยืนยันตัวตน
- รอดำเนินการ
- กำลังตัดสินผล
- อนุมัติหรือปฏิเสธที่นี่แล้ว
- ตัดสินผลจากที่อื่นแล้ว
- หมดอายุ
- ยกเลิกแล้ว
- ไม่ได้รับอนุญาต/ไม่พบ
- เกิดข้อผิดพลาดในการเชื่อมต่อพร้อมให้ลองใหม่
หน้าเรียกใช้ Gateway RPC ไม่ใช่ REST API ที่สองซึ่งไม่มีการยืนยันตัวตน การรีเฟรชเบราว์เซอร์จะอ่านสถานะถาวรอีกครั้ง และจะไม่ใส่ข้อมูลประจำตัวของ Gateway ไว้ใน URL คิวรี หรือส่วน fragment
การอนุญาตและความเป็นส่วนตัว
URL เป็นตัวระบุตำแหน่ง ไม่ใช่อำนาจ การตัดสินผลต้องมี:
- การเชื่อมต่อ Gateway ที่ยืนยันตัวตนแล้ว;
operator.approvalsหรือoperator.admin;- การอนุญาตผู้ตรวจสอบระดับระเบียน
กฎระดับระเบียน:
operator.adminสามารถตรวจสอบได้reviewer_device_idsมีอำนาจชี้ขาดเมื่อมีค่า เฉพาะอุปกรณ์operator.approvalsที่จับคู่และอยู่ในรายการเท่านั้นที่ตรวจสอบได้ อุปกรณ์ที่ส่งคำขอไม่มี สิทธิ์เข้าถึงโดยนัย เว้นแต่จะอยู่ในรายการด้วย- หากไม่มีรายชื่อผู้ตรวจสอบที่ระบุอย่างชัดเจน อุปกรณ์
operator.approvalsที่จับคู่และส่งคำขอสามารถตรวจสอบระเบียนของตนเองได้ - ระเบียนเก่าจริงที่ไม่มีการผูกกับผู้ส่งคำขอหรือผู้ตรวจสอบยังคงให้ อุปกรณ์ที่จับคู่มองเห็นได้อย่างกว้างขวาง เพื่อไม่ให้การอัปเกรดทำให้งานที่รอดำเนินการอยู่แล้วค้างอยู่
- รันไทม์ภายในที่ไม่มีอุปกรณ์สามารถตัดสินผลได้ แต่ไม่สามารถอ่านได้ ผ่านการเชื่อมต่อ
รันไทม์การอนุมัติแบบจำกัดขอบเขต อำนาจดังกล่าวมาจากโทเค็นรันไทม์
ที่เซิร์ฟเวอร์ยืนยันตัวตนแล้วเท่านั้น ฟิลด์
approval.resolveแบบสาธารณะไม่สามารถ สร้างอำนาจนี้ได้ - ความเป็นเจ้าของการเชื่อมต่อสดของผู้ส่งคำขอยังคงใช้ได้กับอะแดปเตอร์รุ่นเก่า โดยจะ ไม่อนุมานจากชื่อไคลเอนต์ที่ตรงกัน
- การเป็นสมาชิกกลุ่มผู้รับเปลี่ยนเฉพาะการนำเสนอเท่านั้น และจะไม่ขยายการอนุญาต
approval.get เปิดเผยเฉพาะโปรเจกชันผู้ตรวจสอบที่ผ่านการทำให้ปลอดภัยแล้ว และละเว้นคีย์การกำหนดเส้นทางต้นทาง/กลุ่มผู้รับภายใน เหตุการณ์ session.approval ของ PR 5 มีปลายทางเดียวคือ sessionKey พร้อม sourceSessionKey หลังจาก Gateway ใช้สแนปช็อตกลุ่มผู้รับที่บันทึกไว้ในฝั่งเซิร์ฟเวอร์ เหตุการณ์ exec/plugin ที่มีอยู่จะคงเพย์โหลดเดิมและผู้รับที่จำกัดไว้จนกว่าผู้ใช้เหตุการณ์จะย้ายระบบ คำขอที่เรียกใช้ได้ การผูกคำสั่ง และการดำเนินการต่อยังคงอยู่ในตัวรอภายในโปรเซสเท่านั้น แถวถาวรมีการนำเสนอที่ปลอดภัย พร้อมข้อมูลเมตาวงจรชีวิต การกำหนดเส้นทาง และการตรวจสอบ โดยจะไม่เก็บค่าสภาพแวดล้อมดิบ ข้อมูลประจำตัว ส่วนหัวการยืนยันตัวตน หรือข้อมูล callback ของช่องทาง
การฉายกลุ่มผู้รับ
คำนวณกลุ่มผู้รับหนึ่งครั้งก่อนแทรกและบันทึกสแนปช็อตที่เรียงลำดับแล้ว ความเป็นเจ้าของเป็นกราฟ ไม่ใช่สายโซ่พาเรนต์เดียวเสมอไป โดยลูกหนึ่งรายการอาจมีทั้งตัวควบคุมปัจจุบันและผู้ส่งคำขอดั้งเดิม และเจ้าของเหล่านั้นอาจนำไปยังรูทที่ต่างกัน
ใช้การเดินแบบกว้างก่อนที่กำหนดผลได้แน่นอน:
- เริ่มต้นคิวด้วยคีย์เซสชันต้นทาง
- สำหรับแต่ละคีย์ที่นำออกจากคิว ให้อ่านแถวรีจิสทรี subagent ล่าสุดและเพิ่มขอบความเป็นเจ้าของที่แตกต่างกันทั้งสองลงในคิวตามลำดับคงที่:
controllerSessionKeyแล้วตามด้วยrequesterSessionKey - เมื่อมีแถวรีจิสทรีที่ใช้ได้ อย่าติดตามสายสืบทอดของรายการเซสชันเพิ่มเติม ซึ่งอาจล้าสมัยหลังการบังคับทิศทาง มิฉะนั้นให้เพิ่มขอบสำรองปัจจุบันเพียงขอบเดียว
parentSessionKey ?? spawnedByลงในคิว - ปรับให้อยู่ในรูปแบบมาตรฐานและขจัดรายการซ้ำขณะเพิ่มลงในคิว เพื่อให้พาธแรกที่สั้นที่สุดชนะ
- หยุดเมื่อครบ 64 คีย์ที่ไม่ซ้ำกัน ขีดจำกัดขนาดกลุ่มผู้รับนี้ยังจำกัดความลึกของการเดินด้วย
แหล่งรีจิสทรีคือ src/agents/subagent-registry-read.ts ฟิลด์ความเป็นเจ้าของกำหนดไว้ใน src/agents/subagent-registry.types.ts ส่วนฟิลด์สำรองของเซสชันกำหนดไว้ใน src/config/sessions/types.ts
โปรเจกชันที่ร้องขอและโปรเจกชันปลายทางใช้กลุ่มผู้รับที่บันทึกไว้ชุดเดียวกัน แม้ว่าความเป็นเจ้าของโฟกัส/ตัวควบคุมจะเปลี่ยนไปขณะการอนุมัติรอดำเนินการ วิธีนี้รับประกันการล้างสถานะปลายทางสำหรับสตรีมเซสชันของกลุ่มผู้รับทุกสตรีมที่ได้รับโปรเจกชันคำขอ การตัดสินผลจะกำหนดเป้าหมายไปยัง ID การอนุมัติต้นทางเสมอ เซสชันของกลุ่มผู้รับจะไม่ได้รับสถานะการอนุมัติที่โคลนมา การล้างข้อความช่องทางที่ส่งต่อยังคงเป็นขั้นตอนติดตามตัวระบุตำแหน่งการส่งมอบแยกต่างหากด้านล่าง
อย่าเขียนข้อความทรานสคริปต์ แทรกพรอมต์ระบบ เริ่มเทิร์นของเจ้าของ หรือปล่อย sessions.changed เพียงเพราะมีการอนุมัติ
การบรรจบกันของพื้นผิวที่ส่งมอบ
ตัวจัดการการอนุมัติแบบเนทีฟเก็บรายการข้อความที่ส่งมอบไว้นานพอที่จะเปลี่ยนหรือเลิกใช้ตัวควบคุมที่ใช้งานอยู่แล้ว ปัจจุบันข้อความการอนุมัติทั่วไปที่ส่งต่อจะทิ้ง MessageReceipt ดังนั้นการตัดสินใจบนพื้นผิวอื่นอาจทำให้ตัวควบคุมเก่ายังคงดูเหมือนรอดำเนินการ ขั้นตอนติดตามแยกต่างหากจะปิดช่องว่างนี้ด้วยตารางลูก operator_approval_deliveries ในฐานข้อมูลสถานะที่ใช้ร่วมกัน
แต่ละแถวเก็บ ID การอนุมัติ ID การส่งมอบที่ไม่ซ้ำกัน ช่องทาง/บัญชี/เส้นทางที่ตรงกันทุกประการ ตัวระบุตำแหน่งข้อความส่วนตัวของช่องทางที่มีขอบเขตจำกัดและผ่านการตรวจสอบ JSON แล้ว เวลาประทับการส่งมอบ และสถานะการทำให้เป็นปลายทาง โดยจะไม่เก็บข้อมูล callback โทเค็นการตัดสินใจ หรือคำขออนุมัติดิบ ช่องทางเป็นเจ้าของการเข้ารหัสตัวระบุตำแหน่งและการแก้ไขข้อความ ส่วน Core เป็นเจ้าของสถานะมาตรฐาน การเลือกเป้าหมาย นโยบายการลองใหม่ และข้อความปลายทางสำรอง
การลงทะเบียนการส่งมอบและการตัดสินผลปลายทางแข่งขันกันได้อย่างปลอดภัย:
- หลังจากการส่งที่รอดำเนินการส่งคืนใบรับ ให้แทรกตัวระบุตำแหน่งการส่งมอบและอ่านสถานะการอนุมัติพาเรนต์ในธุรกรรมเดียว
- หากพาเรนต์อยู่ในสถานะปลายทางแล้ว ให้กำหนดเวลาทำให้เป็นปลายทางทันทีแทนที่จะปล่อยให้การส่งมอบล่าช้ายังคงรอดำเนินการ
- การเปลี่ยนผ่านสู่สถานะปลายทางที่คอมมิตแล้วทุกรายการจะกำหนดเวลาแถวการส่งมอบที่ยังไม่เสร็จสิ้นทั้งหมดแยกต่างหาก การบรอดแคสต์ที่ทิ้งได้ไม่ใช่ตัวกระตุ้น
- ตัวทำให้เป็นปลายทางของช่องทางรายงาน
replaced,retiredหรือunsupportedโดย Replaced จะระงับข้อความปลายทางซ้ำ Retired จะส่งข้อความติดตามปลายทางที่มีอยู่ ส่วนการไม่รองรับหรือความล้มเหลวจะใช้ทางสำรองโดยไม่ย้อนกลับ CAS การอนุมัติ - เมื่อเริ่มต้นระบบ ให้ลองดำเนินการอนุมัติปลายทางที่มีการส่งมอบไม่เสร็จสิ้นอีกครั้ง ทำให้การล้างสถานะทนต่อการรีสตาร์ต Gateway
วงจรชีวิตของการขนส่งนี้เป็นฮุกอะแดปเตอร์การส่งมอบแบบเลือกใช้ ไม่ใช่ตัวเรนเดอร์หรือการดำเนินการข้อความที่โมเดลมองเห็น ปัจจุบันข้อความ QQ แบบ C2C/กลุ่มไม่มี API สำหรับแก้ไข ลบ หรือล้างแป้นพิมพ์ อะแดปเตอร์ดังกล่าวจึงยังไม่รองรับและแสดงความจริงมาตรฐานได้เฉพาะหลังการคลิกในภายหลัง จนกว่าการขนส่งจะมี API สำหรับแก้ไข
ความหมายของการรีสตาร์ต การหมดเวลา และเส้นทาง
การคงอยู่ใน SQLite ไม่ได้หมายความว่าจะดำเนินการต่อได้ การผูกคำสั่ง/เครื่องมือยังคงอยู่ในหน่วยความจำ เพราะอาจมีข้อเท็จจริงของรันไทม์ที่ละเอียดอ่อนด้านความปลอดภัยและไม่ใช่สัญญางานที่ดำเนินการต่อได้
เมื่อ Gateway เริ่มต้น:
- สร้าง epoch รันไทม์ใหม่;
- เปลี่ยนแถวที่รอดำเนินการจาก epoch เก่าไปเป็น
cancelledแบบอะตอมมิก โดยใช้เหตุผลgateway-restart; - เก็บแถวไว้เพื่อให้ URL อธิบายสิ่งที่เกิดขึ้น;
- ห้ามดำเนินการอนุมัติในภายหลังกับการผูกรันไทม์ที่หายไป
ตัวจับเวลาเป็นการเพิ่มประสิทธิภาพสำหรับการปลุก อำนาจของกำหนดเวลาถูกเก็บไว้ใน expires_at_ms การอ่าน การรอ และการตัดสินผลทั้งหมดจะดำเนินการกระทบยอดการหมดอายุ
พฤติกรรมเข้มงวดขั้นสุดท้าย:
- หมดเวลา ->
expired, ปฏิเสธ; - ไม่มีเส้นทาง ->
denied, ปฏิเสธ; - ยกเลิกการรัน ->
cancelled, ปฏิเสธ; - คำตัดสินที่เชื่อถือได้แต่ผิดรูปแบบ ->
denied, ปฏิเสธ; - เฉพาะการตัดสินใจอนุญาตอย่างชัดเจนที่ได้รับอนุญาต ->
allowed
พฤติกรรม exec ที่เผยแพร่อยู่ในปัจจุบันยังคงขัดแย้งกับสัญญานี้:
src/agents/bash-tools.exec-host-shared.tsอาจใช้askFallbackdocs/tools/exec-approvals.mdและdocs/cli/approvals.mdบันทึกพื้นผิวดังกล่าวไว้
ขณะนี้การอนุมัติของ plugin จะปฏิเสธอย่างปลอดภัยเมื่อหมดเวลาและเมื่อคำตัดสินผิดรูปแบบ ฟิลด์รุ่นเก่า
timeoutBehavior ยังคงยอมรับได้แต่จะถูกละเว้น ขั้นตอนติดตามความหมายแบบเข้มงวด
ของ exec ต้องอัปเดตโค้ด ชนิด เอกสาร การทดสอบ และบันทึกการเปลี่ยนแปลงพร้อมกัน โดยมี
การตรวจสอบจากเจ้าของ/ฝ่ายความปลอดภัยอย่างชัดเจน askFallback อาจยังคงอธิบาย
การเลือกนโยบายก่อนเกตระหว่างการย้ายระบบ แต่ต้องไม่เปลี่ยนการหมดเวลาของระเบียน
ที่สร้างและรอดำเนินการอยู่ให้กลายเป็นการอนุมัติ
แผนความเข้ากันได้
- โปรโตคอล Gateway แบบเพิ่มส่วนขยาย โดยไม่เพิ่มเวอร์ชันโปรโตคอล
- คงเมธอดและเหตุการณ์ exec/plugin ที่มีอยู่ไว้ที่ขอบเขตภายนอก
- คง ID ที่มีอยู่ รวมถึงคำนำหน้า
plugin:แต่หยุดใช้คำนำหน้าเป็นข้อมูลชนิด - คงพฤติกรรมคำสั่งข้อความ
/approve - คงฟิลด์ URL/Web App ของปุ่มรุ่นเก่าและการดำเนินการคำสั่งไว้เป็นอินพุตความเข้ากันได้ของ plugin SDK โดยเอาต์พุต Core ใหม่เป็นแบบมีชนิด
- ย้ายช่องทางแบบรวมทั้งหมดและผู้เรียกใช้ภายในทั้งหมดในการเปลี่ยนแปลงการดำเนินการแบบมีชนิดเดียวกัน
- เพิ่มรายการบันทึกการเปลี่ยนแปลงสำหรับ URL/หน้าใหม่และสำหรับการเปลี่ยนแปลงพฤติกรรมการหมดเวลาในภายหลัง
- อย่าเพิ่มการตั้งค่าโหมดการขอข้อมูล
การทยอยเปิดใช้
PR 1: วงจรชีวิตแบบถาวร
- บันทึกการออกแบบนี้
- สคีมา SQLite ที่ใช้ร่วมกัน การสร้าง Kysely สโตร์ และการตัดทิ้งหลัง 30 วัน
- บริการอนุมัติของ Gateway บริดจ์ตัวรอรันไทม์ และการจัดการรายการกำพร้าหลังรีสตาร์ต
approval.get/resolveแบบรวมเป็นหนึ่ง- อะแดปเตอร์เมธอด exec/plugin
- การทดสอบคำตอบแรกชนะ ความทำซ้ำได้โดยไม่เกิดผลเพิ่ม การหมดอายุ การอนุญาต และการใช้งาน
- ยังไม่มีการเปลี่ยนแปลงพฤติกรรมของ UI หรือช่องทาง
PR 2: การดำเนินการแบบมีชนิดและ callback ของช่องทาง
- การดำเนินการอนุมัติ, URL และ Web App แบบระบุชนิด
- ตัวสร้างการนำเสนอหลักและการส่งออก SDK ของ Plugin
- การเข้ารหัสคอลแบ็กที่เป็นข้อมูลส่วนตัวของการขนส่ง พร้อมระบุชนิดเจ้าของอย่างชัดเจน
- การอ้างอิงคอลแบ็กขนาดคงที่แบบคงทนสำหรับ ID มาตรฐานที่เกินขีดจำกัดของการขนส่ง
- การย้ายช่องทางที่รวมมาให้เลิกอนุมานจากข้อความคำสั่งและ ID การอนุมัติ
- สถานะจริงของคำตอบแรกตามมาตรฐานบนพื้นผิวที่คลิก และการอัปเดตสถานะสิ้นสุดแบบเนทีฟที่ยังทำงานอยู่โดยพยายามให้ดีที่สุด ส่วนการทำให้ข้อความช่องทางเข้าสู่สถานะสิ้นสุดอย่างคงทนยังเป็นงานติดตามผล
- การทดสอบ SDK และช่องทางที่รวมมา
PR 3: ดีปลิงก์ของ UI ควบคุม
- หน้าการอนุมัติแบบสแตนด์อโลนที่ผ่านการตรวจสอบสิทธิ์ และการกำหนดเส้นทางเริ่มต้นที่คำนึงถึงพาธฐาน
- การผูกกับ Gateway ที่ให้บริการโดยไม่แก้ไขการเลือกรีโมตที่ผู้ปฏิบัติงานบันทึกไว้
- เนมสเปซ HTTP สำหรับการอนุมัติที่แกนหลักเป็นเจ้าของ รวมถึง ID ที่มีลักษณะคล้ายแอสเซ็ต
- เพย์โหลด URL ที่ Gateway สร้าง และการสำรวจสถานะรอดำเนินการจนกว่าจะส่งมอบเหตุการณ์วงจรชีวิต
- หลักฐานสำหรับความกว้างระดับมือถือ การเชื่อมต่อใหม่ คำตอบที่แข่งขันกัน การโหลดใหม่ และพาธที่เมานต์
PR 4: ไคลเอนต์แบบเนทีฟ
- พื้นผิวการตรวจสอบบน iOS และ Android ใช้
approval.get/resolveที่รับรู้ชนิด ส่วน watchOS ถ่ายทอดพรอมต์และการตัดสินใจที่ปลอดภัยสำหรับผู้ตรวจสอบผ่าน iPhone ที่จับคู่ - Watch เสนอการตัดสินใจสำหรับ exec ที่สัญญารีเลย์แบบกะทัดรัดรองรับ ได้แก่ อนุญาตครั้งเดียวและปฏิเสธ
- สถานะจริงของคำตอบแรกตามมาตรฐานในสถานะสิ้นสุดจะแทนที่สถานะการตัดสินใจที่พยายามดำเนินการภายในเครื่อง
- การตอบรับการแก้ไขที่สูญหายหรือกำกวมจะระงับตัวควบคุมไว้จนกว่าจะอ่านสถานะมาตรฐานกลับมา
- อินสแตนซ์ Gateway v4 ที่เผยแพร่ก่อนหน้านี้ยังคงรองรับการตรวจสอบ exec ผ่านวิธีสำรองแบบเดิมที่มีขอบเขตแคบ ส่วนสถานะสิ้นสุดที่คงไว้ข้ามพื้นผิวต้องใช้เมธอดแบบรวม
- คำเตือนสำหรับผู้ตรวจสอบและบริบทเจ้าของยังคงมองเห็นได้บน iPhone, Watch และ Android
- หลักฐานจากยูนิตเนทีฟ บิลด์ และแพลตฟอร์ม
PR 5: การเผยแพร่วงจรชีวิตไปยังบรรพบุรุษ
- การส่งสถานะรอดำเนินการ/สิ้นสุดของ
session.approvalจากสแนปช็อตผู้รับที่บันทึกอย่างคงทนใน PR 1 - การสมัครรับข้อมูลเฉพาะเซสชัน การเล่นซ้ำเมื่อเชื่อมต่อใหม่ และทูมบ์สโตนสถานะสิ้นสุด โดยไม่แก้ไขทรานสคริปต์หรือปลุกเอเจนต์
- คอลแบ็กวงจรชีวิตทำงานหลังการแทรก/CAS แบบคงทน และจะไม่กลายเป็นผู้มีอำนาจอนุมัติ
- หลักฐานสำหรับซับเอเจนต์แบบซ้อนและการเชื่อมต่อใหม่
PR 6: พฤติกรรมปิดเมื่อเกิดความล้มเหลว
- ย้าย
node-invoke-plugin-policy.tsและโบรกเกอร์ Plugin แบบฝังออกจากการมีอำนาจซ้ำซ้อน - ความหมายเชิงความหมายที่เข้มงวดสำหรับการหมดเวลา ข้อมูลผิดรูป ไม่มีเส้นทาง การผูก และการใช้สิทธิ์อนุญาตครั้งเดียว
- เลิกใช้การตั้งค่าการหมดเวลาแบบผ่อนปรนที่เผยแพร่แล้ว โดยไม่ปฏิบัติตามการตั้งค่าเหล่านั้นหลังจากคำขออยู่ในสถานะรอดำเนินการ
- หลักฐานสำหรับการแข่งขันหลายพื้นผิวและการฉีดความล้มเหลว
งานติดตามผล: การล้างข้อความรีโมตอย่างคงทน
- บันทึกตัวระบุตำแหน่งการส่งต่ออย่างคงทน และทำให้ทุกข้อความช่องทางที่ส่งแล้วเข้าสู่สถานะสิ้นสุดหลังการรีสตาร์ต
- แยกวงจรชีวิตการขนส่งนี้ออกจากอำนาจอนุมัติมาตรฐานและการดำเนินการนำเสนอแบบระบุชนิด
การทดสอบ
ความครอบคลุมเฉพาะจุดที่จำเป็น:
- การเปิด SQLite ใหม่ยังคงการฉายสถานะรอดำเนินการและสถานะสิ้นสุด
- ตัวแก้ไขพร้อมกันสองตัวให้ผู้ชนะ CAS เพียงหนึ่งรายเท่านั้น
- การลองใหม่ด้วยการตัดสินใจเดิมสำเร็จแบบไอดิมโพเทนต์ ส่วนการลองใหม่ที่ขัดแย้งจะคืนค่าผู้ชนะที่บันทึกไว้
- การแก้ไขเมื่อถึงหรือหลังเส้นตายไม่สามารถอนุมัติได้
allow-onceใช้ได้เพียงครั้งเดียวโดยไม่ลบสถานะการตรวจสอบสถานะสิ้นสุด- การเริ่มต้นยกเลิกยุครันไทม์ที่เก่ากว่า
- การค้นหาและการแก้ไขที่ไม่ได้รับอนุญาตจะไม่เปิดเผยว่ามีเรกคอร์ดอยู่หรือไม่
- รายการอนุญาตผู้ตรวจสอบที่ระบุชัดเจนและพฤติกรรม
operator.approvalsที่จับคู่ทั่วไป - เมธอดแบบเดิมของ exec และ Plugin ใช้สโตร์เดียวกัน
- สคีมาคำขอ/รายการ/รับ/แก้ไขของ Gateway และเพย์โหลดเหตุการณ์แบบเพิ่มเติม
- การทำให้การดำเนินการแบบระบุชนิดเป็นมาตรฐาน การเรนเดอร์สำรอง การส่งออก SDK และสวิตช์ช่องทางที่รวมมา
- การเข้ารหัสคอลแบ็กของ Telegram มีข้อมูลส่วนตัวของการขนส่งและไม่มีการอนุมานสตริงคำสั่ง
- เจ้าของที่เป็นลูกโดยตรง เจ้าของตัวควบคุม/ผู้ร้องขอแบบแตกแขนง เจ้าของแบบซ้อน การมอบหมายใหม่ ทางเลือกสำรองของฟิลด์เซสชัน วงจร และขีดจำกัดขนาดผู้รับ
- อาร์เรย์ผู้รับที่ร้องขอและที่เข้าสู่สถานะสิ้นสุดเหมือนกันทุกประการ
- การฉายข้อมูลเจ้าของไม่ทำให้ทรานสคริปต์เปลี่ยนแปลงหรือปลุกเอเจนต์
- เส้นทาง UI ควบคุมทำงานที่
/และพาธฐานที่กำหนดค่าไว้ การรีเฟรชแสดงสถานะจริงที่รอดำเนินการหรือสิ้นสุด - คำตอบจาก UI ควบคุมและ Telegram พร้อมกันแสดงผู้ชนะหนึ่งราย และแสดง "แก้ไขที่อื่นแล้ว" สำหรับฝ่ายที่แพ้
- ตัวระบุการอนุมัติแบบเนทีฟและตัวระบุเจ้าของ Gateway รักษาไบต์ UTF-8 ไว้อย่างถูกต้องทุกประการตลอดการกำหนดเส้นทางและการกระทบยอด
- การเจรจาตระกูล RPC แบบเนทีฟจะปักหมุดตระกูลมาตรฐานหรือแบบเดิมหนึ่งตระกูลต่อเส้นทาง Gateway ที่รับเข้า และไม่ลดระดับอย่างเงียบ ๆ หลังเริ่มใช้งาน
- การตอบรับการแก้ไขแบบเนทีฟที่สูญหายจะระงับการดำเนินการจนกว่าจะอ่านสถานะมาตรฐานกลับมา การอ่านกลับที่ล้มเหลวต้องไม่สร้างผู้ชนะขึ้นเองหรือยืนยันการรีเฟรชของ Watch
- ยอมรับความสัมพันธ์ของคำขอสแนปช็อต Watch เฉพาะสำหรับเจ้าของ Gateway ที่จับคู่ตรงกันทุกประการและการอ่านสถานะมาตรฐานกลับบน iPhone ที่เสร็จสมบูรณ์แล้ว
- หลักฐานเส้นทางผู้ใช้ผ่าน Testbox/Crabbox รวมถึงหน้าการอนุมัติความกว้างระดับมือถือ การล้างการดำเนินการของ Telegram และการเดินทางไปกลับหนึ่งรอบสำหรับสถานะรอดำเนินการ/การแก้ไข/ผู้แพ้ที่ตอบช้า ครอบคลุม Android, iPhone และ Watch
ความสามารถในการสังเกตการณ์
ส่งออกบันทึกการเปลี่ยนสถานะแบบมีโครงสร้างและไม่มีเนื้อหา โดยมี ID การอนุมัติ ชนิด คีย์เซสชันต้นทาง สถานะ เหตุผล และเวลาแฝง ห้ามบันทึกตัวอย่างแสดงผลหรือการผูกแบบดิบ
ติดตาม:
- จำนวนที่ร้องขอแยกตามชนิด
- จำนวนสถานะสิ้นสุดแยกตามชนิด/สถานะ/เหตุผล
- เกจสถานะรอดำเนินการ
- เวลาแฝงตั้งแต่คำขอจนถึงสถานะสิ้นสุด
- ผลลัพธ์การแข่งขันในการแก้ไข: ผู้ชนะ การลองใหม่แบบไอดิมโพเทนต์ ความขัดแย้ง หมดอายุ
- จำนวนเส้นทางการส่งและการปฏิเสธเนื่องจากไม่มีเส้นทาง
- การยกเลิกรายการกำพร้าเมื่อเริ่มต้น
- ขนาดผู้รับ
การเปลี่ยนสถานะที่คอมมิตแล้วถือว่าสำเร็จ แม้ว่าการส่งเหตุการณ์ภายหลังจะล้มเหลว ผู้สมัครรับวงจรชีวิตกู้คืนผ่านการเล่นซ้ำใน PR 5 และการค้นหาแบบมาตรฐาน การทำให้ข้อความช่องทางเข้าสู่สถานะสิ้นสุดอย่างคงทนยังคงเป็นงานติดตามผลแยกต่างหากข้างต้น
การตัดสินใจที่ยังเปิดอยู่
- ต้นทาง UI ควบคุมที่เข้าถึงได้จากภายนอก ทุกสแนปช็อตมี
urlPathแบบสัมพัทธ์ที่เสถียร อาจประกาศ URL แบบสัมบูรณ์ได้เฉพาะจากตำแหน่ง Tailscale Serve/Funnel ที่แคชไว้หลังจากเปิดเผย Gateway สำเร็จแล้วเท่านั้น โดยallowedOrigins, ส่วนหัว Host ของคำขอ,gateway.remote.urlและตัวเลือก loopback/LAN ที่ใช้แสดงผลเท่านั้นไม่ใช่ต้นทางมาตรฐาน Telegram สามารถใช้ตัวห่อ Mini App ที่ผ่านการตรวจสอบสิทธิ์เพื่อคงพาธการอนุมัติไว้ตลอดการบูตสแตรป พร็อกซีย้อนกลับตามอำเภอใจยังคงใช้ได้เฉพาะแบบสัมพัทธ์ จนกว่าจะมีสัญญา URL สาธารณะที่ระบุชัดเจนและผ่านการตรวจสอบแยกต่างหาก ห้ามให้ช่องทางคาดเดาต้นทาง - จุดเปลี่ยนความเข้ากันได้ของการหมดเวลาแบบเข้มงวดสำหรับ exec ขณะนี้การหมดเวลาการอนุมัติของ Plugin จะปิดเมื่อเกิดความล้มเหลว และเลิกใช้
timeoutBehaviorแล้ว สัญญาaskFallbackที่เผยแพร่แล้วและยังเหลืออยู่ต้องผ่านการตรวจสอบจากเจ้าของ/ฝ่ายความปลอดภัยอย่างชัดเจน มีบันทึกการเปลี่ยนแปลง เอกสาร และการตัดสินใจเรื่องการย้าย/เลิกใช้ ก่อนที่จะหยุดอนุญาตการดำเนินการหลังคำขอที่รอดำเนินการหมดเวลา - โหมดฝังตัวที่ไม่มี Gateway คำแนะนำ: ให้ใช้เฉพาะภายในเครื่องในช่วงแรก จากนั้นทำให้เป็นไคลเอนต์ของบริการมาตรฐานเมื่อมี Gateway อย่าโฆษณาดีปลิงก์ที่ไม่มีเซิร์ฟเวอร์ใดแก้ไขได้