- variant ที่ใช้ได้
- mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ไม่รวมอยู่ในชุดเอกสารของ mtb-only (ที่นั่นไม่ได้ลิงก์ libbento_mpy.a)
เป้าหมายของหัวข้อนี้
ท่องลำดับของ gate (ด่านกั้นเชิงความปลอดภัย) ให้ได้ — circuit breaker → trust → rate check → rate record — และรู้ว่าเหตุใดลำดับนี้จึงตายตัว จับคู่ claw_cb_success() กับ claw_cb_failure() ให้ถูกต้องรอบการ raise ที่ไม่คืนค่ากลับ ยกระดับ trust ก่อนการ connect และคืนค่าเดิมในทุกเส้นทางที่ล้มเหลว ตรวจสอบแต่ละ gate จาก REPL ด้วยสตริง RuntimeError ที่มันโยนออกมา
ลำดับการทำงานจริงของเฟิร์มแวร์
การ init เป็น idempotent และมีทางเข้าเดียว:
static void bentoclaw_ensure_init(void) {
if (s_module_inited) return;
for (size_t i = 0; i < TOOL_COUNT; i++) {
if (s_tools[i].rate_per_min > 0) {
}
}
s_module_inited = true;
}
ลำดับของ gate — snippet ที่รับน้ำหนักมากที่สุดในโมดูลนี้:
s_error_count++;
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("circuit breaker open — cooldown active"));
}
s_error_count++;
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("tool risk exceeds transport trust level"));
}
s_error_count++;
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("rate limit exceeded for this tool"));
}
การตรวจ ไม่กินโควตา — claw_rate_check() และ claw_rate_record() เป็นการเรียกคนละครั้งบน found->name เดียวกัน และจะไปถึง record ก็ต่อเมื่อผ่าน gate ครบทั้งสามแล้วเท่านั้น s_error_count++ มาก่อนการ raise ทุกครั้ง
การจับคู่สำเร็จ/ล้มเหลว ต้องเรียก claw_cb_failure() ก่อน mp_raise_msg ที่ไม่คืนค่ากลับทั้งสองฟังก์ชันเป็น void:
if (resp_len < 0) {
s_agent_state = CLAW_STATE_ERROR;
s_error_count++;
claw_ipc_send_ui(CLAW_UI_ERROR, "Backend error", 13);
snprintf(s_last_result, sizeof(s_last_result), "error");
claw_ipc_send_ui(CLAW_UI_LAST_RESULT, s_last_result, strlen(s_last_result));
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("HTTPS request failed"));
}
s_agent_state = CLAW_STATE_IDLE;
การยกระดับ trust และการคืนค่าเดิม trust ยกขึ้นเป็น CLAW_TRUST_HTTPS ก่อนการพยายาม connect และรีเซ็ตกลับเป็น CLAW_TRUST_USB ภายใน else เพื่อไม่ให้การ connect ที่ล้มเหลวทิ้งเครื่องมือความเสี่ยงสูงไว้ในสถานะเปิด:
claw_ipc_init();
claw_ipc_send_ui(CLAW_UI_STATUS_TEXT, "Connecting...", 13);
if (ok) {
claw_ipc_send_ui(CLAW_UI_STATUS_TEXT, "Online (HTTPS)", 14);
} else {
claw_ipc_send_ui(CLAW_UI_STATUS_TEXT, "Connect failed", 14);
}
static mp_obj_t bentoclaw_disconnect(void) {
if (claw_ipc_initialized) {
claw_ipc_send_ui(CLAW_UI_STATUS_TEXT, "Offline", 7);
}
return mp_const_none;
}
ส่วนที่เรียกดูสถานะ — claw_cb_state(), claw_trust_get(), claw_cb_cooldown_remaining() รวมอยู่ในฟังก์ชันเดียวที่จบในตัว:
static mp_obj_t bentoclaw_safety(void) {
bentoclaw_ensure_init();
mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(4));
static const char *cb_names[] = { "closed", "open", "half-open" };
const char *cb_str = (cb < 3) ? cb_names[cb] : "unknown";
static const char *trust_names[] = { "none", "https", "usb" };
const char *trust_str = (trust < 3) ? trust_names[trust] : "unknown";
mp_obj_dict_store(MP_OBJ_FROM_PTR(d),
MP_OBJ_NEW_QSTR(MP_QSTR_circuit_breaker),
mp_obj_new_str(cb_str, strlen(cb_str)));
mp_obj_dict_store(MP_OBJ_FROM_PTR(d),
MP_OBJ_NEW_QSTR(MP_QSTR_cooldown_ms),
claw_memory_set() เป็น binding แบบ bool ธรรมดา:
static mp_obj_t bentoclaw_remember(mp_obj_t key_obj, mp_obj_t val_obj) {
bentoclaw_ensure_init();
const char *key = mp_obj_str_get_str(key_obj);
const char *val = mp_obj_str_get_str(val_obj);
return mp_obj_new_bool(ok);
}
ทีละขั้น
ขั้นที่ 1 — อ่านสถานะความปลอดภัยตั้งต้น
>>> import bentoclaw
>>> bentoclaw.safety()
สิ่งที่ควรสังเกต dict ที่มี cb = "closed", trust = "usb" (หรือ "none") และ cooldown_ms = 0 ตารางชื่อมีตัวกันขอบเขต (คืน "unknown" สำหรับค่าที่อยู่นอกช่วง)
ขั้นที่ 2 — ทำให้ trust gate ทำงาน
เรียกเครื่องมือที่ประกาศระดับความเสี่ยงไว้สูงกว่าระดับ trust ปัจจุบัน ในขณะที่ยังไม่ได้เชื่อมต่อ
สิ่งที่ควรสังเกต RuntimeError: tool risk exceeds transport trust level และ safety()['trust'] ไม่เปลี่ยน — trust gate ปฏิเสธเท่านั้น ไม่ไปแก้ค่า
ขั้นที่ 3 — ทำให้ rate gate ทำงาน
เรียกเครื่องมือที่จำกัดอัตราซ้ำ ๆ ภายในหนึ่งนาที
สิ่งที่ควรสังเกต RuntimeError: rate limit exceeded ในการเรียกครั้งแรกที่เกิน rate_per_min ของเครื่องมือนั้น ค่าจำกัดมาจาก registry ตอน init (ลูป claw_rate_set เฉพาะเมื่อ rate_per_min > 0)
ขั้นที่ 4 — เปิด breaker แล้วเฝ้าดู cooldown
ทำให้เกิดความล้มเหลวติดต่อกัน (ปลายทาง HTTPS ที่ตัดการเชื่อมต่อไว้ก็เพียงพอ)
สิ่งที่ควรสังเกต RuntimeError: circuit breaker open — cooldown active และ safety()['cb'] = "open" โดย cooldown_ms นับถอยหลัง ความล้มเหลวแต่ละครั้งผ่าน claw_cb_failure() ก่อนการ raise ของมัน ส่วนความสำเร็จครั้งถัดมาผ่าน claw_cb_success() และปิด breaker ผ่านสถานะ "half-open"
กับดัก
- Warning
- ลำดับนี้ต่อรองไม่ได้ breaker ถูกตรวจก่อน trust เพื่อไม่ให้ transport ที่มี trust สูงเลี่ยง breaker ที่เปิดอยู่ได้ และ rate บันทึกเป็นลำดับสุดท้ายเพื่อไม่ให้การเรียกที่ถูกปฏิเสธกินโควตา
-
การ raise โดยไม่เรียก claw_cb_failure() ก่อน ทำให้ breaker มองไม่เห็นความล้มเหลวนั้น — mp_raise_msg ไม่คืนค่ากลับ
-
CLAW_TRUST_HTTPS ทุกจุดต้องมี CLAW_TRUST_USB เป็นคู่ของมัน บนเส้นทางที่ล้มเหลวและเส้นทางตัดการเชื่อมต่อ (modbentoclaw.c:487, :2369) claw_https_disconnect() ทำงานโดยไม่มีเงื่อนไขและต้องตามด้วยการรีเซ็ต trust
-
claw_memory_get, claw_session_dirty, claw_session_flush ส่งออกมาโดยไม่มีผู้เรียกเลยตัวอย่างของทั้งสามเป็นตัวอย่างที่เขียนขึ้นเองและระบุไว้เช่นนั้น
กล่อง variant
mtb-mpy เท่านั้น บน mtb-only ไม่มีส่วนที่เรียกใช้ได้ของ BentoClaw