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 เป็นเจ้าของวงจรชีวิต:

  1. เอเจนต์ ฮุกของ Plugin หรือนโยบาย Node จัดเตรียมคำขอเฉพาะชนิดและการผูกการดำเนินการภายในโปรเซส
  2. Gateway ตรวจสอบคำขอและสร้างการฉายข้อมูลสำหรับผู้ตรวจสอบที่ผ่านการกรอง
  3. บริการการอนุมัติคำนวณกลุ่มผู้รับที่เป็นต้นทาง/เจ้าของ แทรกแถวข้อมูลหลัก แล้วลงทะเบียนตัวรอภายในโปรเซส
  4. หลังจากแทรกข้อมูลถาวรแล้ว Gateway จะเผยแพร่เหตุการณ์การอนุมัติที่มีอยู่ การฉายข้อมูลเซสชัน การแจ้งเตือนช่องทาง และการพุชแบบเนทีฟ
  5. ทุกพื้นผิวตัดสินผลผ่านบริการเดียวกัน
  6. บริการคอมมิตการเปลี่ยนผ่านปลายทางหนึ่งครั้ง ปลุกตัวรอของรันไทม์ และเผยแพร่การฉายข้อมูลปลายทาง
  7. การส่งเหตุการณ์ที่ล้มเหลวจะไม่ย้อนกลับการตัดสินใจที่คอมมิตแล้ว ไคลเอนต์กู้คืนผ่าน 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 ที่เทียบเท่ากับ:

sql
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:

ts
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.requested
  • exec.approval.resolved
  • plugin.approval.requested
  • plugin.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:

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 เป็นตัวระบุตำแหน่ง ไม่ใช่อำนาจ การตัดสินผลต้องมี:

  1. การเชื่อมต่อ Gateway ที่ยืนยันตัวตนแล้ว;
  2. operator.approvals หรือ operator.admin;
  3. การอนุญาตผู้ตรวจสอบระดับระเบียน

กฎระดับระเบียน:

  • operator.admin สามารถตรวจสอบได้
  • reviewer_device_ids มีอำนาจชี้ขาดเมื่อมีค่า เฉพาะอุปกรณ์ operator.approvals ที่จับคู่และอยู่ในรายการเท่านั้นที่ตรวจสอบได้ อุปกรณ์ที่ส่งคำขอไม่มี สิทธิ์เข้าถึงโดยนัย เว้นแต่จะอยู่ในรายการด้วย
  • หากไม่มีรายชื่อผู้ตรวจสอบที่ระบุอย่างชัดเจน อุปกรณ์ operator.approvals ที่จับคู่และส่งคำขอสามารถตรวจสอบระเบียนของตนเองได้
  • ระเบียนเก่าจริงที่ไม่มีการผูกกับผู้ส่งคำขอหรือผู้ตรวจสอบยังคงให้ อุปกรณ์ที่จับคู่มองเห็นได้อย่างกว้างขวาง เพื่อไม่ให้การอัปเกรดทำให้งานที่รอดำเนินการอยู่แล้วค้างอยู่
  • รันไทม์ภายในที่ไม่มีอุปกรณ์สามารถตัดสินผลได้ แต่ไม่สามารถอ่านได้ ผ่านการเชื่อมต่อ รันไทม์การอนุมัติแบบจำกัดขอบเขต อำนาจดังกล่าวมาจากโทเค็นรันไทม์ ที่เซิร์ฟเวอร์ยืนยันตัวตนแล้วเท่านั้น ฟิลด์ approval.resolve แบบสาธารณะไม่สามารถ สร้างอำนาจนี้ได้
  • ความเป็นเจ้าของการเชื่อมต่อสดของผู้ส่งคำขอยังคงใช้ได้กับอะแดปเตอร์รุ่นเก่า โดยจะ ไม่อนุมานจากชื่อไคลเอนต์ที่ตรงกัน
  • การเป็นสมาชิกกลุ่มผู้รับเปลี่ยนเฉพาะการนำเสนอเท่านั้น และจะไม่ขยายการอนุญาต

approval.get เปิดเผยเฉพาะโปรเจกชันผู้ตรวจสอบที่ผ่านการทำให้ปลอดภัยแล้ว และละเว้นคีย์การกำหนดเส้นทางต้นทาง/กลุ่มผู้รับภายใน เหตุการณ์ session.approval ของ PR 5 มีปลายทางเดียวคือ sessionKey พร้อม sourceSessionKey หลังจาก Gateway ใช้สแนปช็อตกลุ่มผู้รับที่บันทึกไว้ในฝั่งเซิร์ฟเวอร์ เหตุการณ์ exec/plugin ที่มีอยู่จะคงเพย์โหลดเดิมและผู้รับที่จำกัดไว้จนกว่าผู้ใช้เหตุการณ์จะย้ายระบบ คำขอที่เรียกใช้ได้ การผูกคำสั่ง และการดำเนินการต่อยังคงอยู่ในตัวรอภายในโปรเซสเท่านั้น แถวถาวรมีการนำเสนอที่ปลอดภัย พร้อมข้อมูลเมตาวงจรชีวิต การกำหนดเส้นทาง และการตรวจสอบ โดยจะไม่เก็บค่าสภาพแวดล้อมดิบ ข้อมูลประจำตัว ส่วนหัวการยืนยันตัวตน หรือข้อมูล callback ของช่องทาง

การฉายกลุ่มผู้รับ

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

ใช้การเดินแบบกว้างก่อนที่กำหนดผลได้แน่นอน:

  1. เริ่มต้นคิวด้วยคีย์เซสชันต้นทาง
  2. สำหรับแต่ละคีย์ที่นำออกจากคิว ให้อ่านแถวรีจิสทรี subagent ล่าสุดและเพิ่มขอบความเป็นเจ้าของที่แตกต่างกันทั้งสองลงในคิวตามลำดับคงที่: controllerSessionKey แล้วตามด้วย requesterSessionKey
  3. เมื่อมีแถวรีจิสทรีที่ใช้ได้ อย่าติดตามสายสืบทอดของรายการเซสชันเพิ่มเติม ซึ่งอาจล้าสมัยหลังการบังคับทิศทาง มิฉะนั้นให้เพิ่มขอบสำรองปัจจุบันเพียงขอบเดียว parentSessionKey ?? spawnedBy ลงในคิว
  4. ปรับให้อยู่ในรูปแบบมาตรฐานและขจัดรายการซ้ำขณะเพิ่มลงในคิว เพื่อให้พาธแรกที่สั้นที่สุดชนะ
  5. หยุดเมื่อครบ 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 เป็นเจ้าของสถานะมาตรฐาน การเลือกเป้าหมาย นโยบายการลองใหม่ และข้อความปลายทางสำรอง

การลงทะเบียนการส่งมอบและการตัดสินผลปลายทางแข่งขันกันได้อย่างปลอดภัย:

  1. หลังจากการส่งที่รอดำเนินการส่งคืนใบรับ ให้แทรกตัวระบุตำแหน่งการส่งมอบและอ่านสถานะการอนุมัติพาเรนต์ในธุรกรรมเดียว
  2. หากพาเรนต์อยู่ในสถานะปลายทางแล้ว ให้กำหนดเวลาทำให้เป็นปลายทางทันทีแทนที่จะปล่อยให้การส่งมอบล่าช้ายังคงรอดำเนินการ
  3. การเปลี่ยนผ่านสู่สถานะปลายทางที่คอมมิตแล้วทุกรายการจะกำหนดเวลาแถวการส่งมอบที่ยังไม่เสร็จสิ้นทั้งหมดแยกต่างหาก การบรอดแคสต์ที่ทิ้งได้ไม่ใช่ตัวกระตุ้น
  4. ตัวทำให้เป็นปลายทางของช่องทางรายงาน replaced, retired หรือ unsupported โดย Replaced จะระงับข้อความปลายทางซ้ำ Retired จะส่งข้อความติดตามปลายทางที่มีอยู่ ส่วนการไม่รองรับหรือความล้มเหลวจะใช้ทางสำรองโดยไม่ย้อนกลับ CAS การอนุมัติ
  5. เมื่อเริ่มต้นระบบ ให้ลองดำเนินการอนุมัติปลายทางที่มีการส่งมอบไม่เสร็จสิ้นอีกครั้ง ทำให้การล้างสถานะทนต่อการรีสตาร์ต 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 อาจใช้ askFallback
  • docs/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 และการค้นหาแบบมาตรฐาน การทำให้ข้อความช่องทางเข้าสู่สถานะสิ้นสุดอย่างคงทนยังคงเป็นงานติดตามผลแยกต่างหากข้างต้น

การตัดสินใจที่ยังเปิดอยู่

  1. ต้นทาง UI ควบคุมที่เข้าถึงได้จากภายนอก ทุกสแนปช็อตมี urlPath แบบสัมพัทธ์ที่เสถียร อาจประกาศ URL แบบสัมบูรณ์ได้เฉพาะจากตำแหน่ง Tailscale Serve/Funnel ที่แคชไว้หลังจากเปิดเผย Gateway สำเร็จแล้วเท่านั้น โดย allowedOrigins, ส่วนหัว Host ของคำขอ, gateway.remote.url และตัวเลือก loopback/LAN ที่ใช้แสดงผลเท่านั้นไม่ใช่ต้นทางมาตรฐาน Telegram สามารถใช้ตัวห่อ Mini App ที่ผ่านการตรวจสอบสิทธิ์เพื่อคงพาธการอนุมัติไว้ตลอดการบูตสแตรป พร็อกซีย้อนกลับตามอำเภอใจยังคงใช้ได้เฉพาะแบบสัมพัทธ์ จนกว่าจะมีสัญญา URL สาธารณะที่ระบุชัดเจนและผ่านการตรวจสอบแยกต่างหาก ห้ามให้ช่องทางคาดเดาต้นทาง
  2. จุดเปลี่ยนความเข้ากันได้ของการหมดเวลาแบบเข้มงวดสำหรับ exec ขณะนี้การหมดเวลาการอนุมัติของ Plugin จะปิดเมื่อเกิดความล้มเหลว และเลิกใช้ timeoutBehavior แล้ว สัญญา askFallback ที่เผยแพร่แล้วและยังเหลืออยู่ต้องผ่านการตรวจสอบจากเจ้าของ/ฝ่ายความปลอดภัยอย่างชัดเจน มีบันทึกการเปลี่ยนแปลง เอกสาร และการตัดสินใจเรื่องการย้าย/เลิกใช้ ก่อนที่จะหยุดอนุญาตการดำเนินการหลังคำขอที่รอดำเนินการหมดเวลา
  3. โหมดฝังตัวที่ไม่มี Gateway คำแนะนำ: ให้ใช้เฉพาะภายในเครื่องในช่วงแรก จากนั้นทำให้เป็นไคลเอนต์ของบริการมาตรฐานเมื่อมี Gateway อย่าโฆษณาดีปลิงก์ที่ไม่มีเซิร์ฟเวอร์ใดแก้ไขได้
Was this useful?
On this page

On this page