SDK สำหรับ TESAIoT Dev Kit
คู่มืออ้างอิง API และ Tutorial (MTB & µPython)
Loading...
Searching...
No Matches
เซสชันและที่เก็บ memory

Functions

void claw_session_init (void)
 เริ่มต้นระบบย่อยเซสชัน; ถูกเรียกเพียงครั้งเดียวผ่าน bentoclaw_ensure_init()
bool claw_session_add (claw_role_t role, const char *content)
 ผนวกข้อความหนึ่งรายการและตัด ring ให้เหลือเท่ากับ CLAW_SESSION_MAX_MSGS
uint16_t claw_session_count (void)
 จำนวนข้อความที่อยู่ใน ring ขณะนั้น
void claw_session_clear (void)
 ลบ /.bentoclaw_session และล้าง ring ให้ว่าง; ที่เก็บ memory ไม่ถูกแตะ
size_t claw_session_build_context (char *out_buf, size_t out_max)
 เรนเดอร์รอบสนทนาล่าสุดพร้อม memory ลงในบัฟเฟอร์ที่ผู้เรียกจัดหามาให้; ยังไม่ผ่านการ escape แบบ JSON
bool claw_memory_set (const char *key, const char *value)
 เก็บคู่คีย์/ค่าแบบถาวรที่อยู่รอดทั้งการล้างเซสชันและ soft reset
bool claw_memory_get (const char *key, char *out_value, size_t out_max)
 ค้นหาคีย์ใน /.bentoclaw_memory; คืน false เมื่อไม่พบ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ
bool claw_session_dirty (void)
 predicate ที่ต้นทุนต่ำ: ring ใน RAM มีการเปลี่ยนแปลงที่ยังไม่ได้เขียนลงจริงหรือไม่ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ
bool claw_session_flush (void)
 เขียน ring ที่ยังค้างอยู่ลงหน่วยความจำแฟลช จาก MicroPython task context เท่านั้น ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

Detailed Description

9 ฟังก์ชันที่ทำงานบนไฟล์ LittleFS 2 ไฟล์: /.bentoclaw_session ซึ่งเป็น ring buffer แบบ JSONL เก็บรอบสนทนาล่าสุด CLAW_SESSION_MAX_MSGS (10) รอบ และ /.bentoclaw_memory ซึ่งเป็นที่เก็บคีย์/ค่าแบบถาวรที่อยู่รอด claw_session_clear() ตัว implementation คือ claw_session.c คอมไพล์รวมอยู่ใน libbento_mpy.a และไม่ได้ส่งมอบมาเป็นซอร์ส; มันทำ I/O กับไฟล์ด้วยการรัน open() ของ Python ผ่าน VFS bridge ของ MicroPython ด้วยเหตุนี้ทุกฟังก์ชันในกลุ่มนี้จึงต้องอยู่ใน MicroPython task context และระบบย่อยนี้จึงไม่มีการจับ lock เลย — มีเพียง MicroPython task เท่านั้นที่แตะมัน

claw_session_init() ทำงานครั้งเดียวจาก bentoclaw_ensure_init() ที่เป็น idempotent (ดู Claw safety gates); ไม่มีการเริ่มต้นระบบทางอื่นเปิดให้เรียก

6 ใน 9 ตัวมี call site อยู่จริงใน modbentoclaw.c ส่วนอีก 3 ตัว คือ claw_memory_get(), claw_session_dirty(), claw_session_flush() ไม่มีผู้เรียกที่ใดเลย ทั้งในเทมเพลตและในทรีที่เก็บไว้ใน archive; ตัวอย่างของทั้งสามเป็นตัวอย่างที่เขียนขึ้นเองและกำกับไว้เช่นนั้น

variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)

Function Documentation

◆ claw_session_init()

void claw_session_init ( void )

เริ่มต้นระบบย่อยเซสชัน; ถูกเรียกเพียงครั้งเดียวผ่าน bentoclaw_ensure_init()

ข้อกำหนดการเรียกใช้
เริ่มต้นระบบย่อยเซสชัน (สถานะ ring ใน RAM ส่วนไฟล์จะถูกแตะแบบ lazy เมื่อจำเป็น) ถูกเรียก เพียงครั้งเดียว จาก bentoclaw_ensure_init() ที่เป็น idempotent ถัดจาก claw_rate_init() และ claw_cb_init() ทำงานใน MicroPython task context; เป็น void; ไม่มีการจับ lock ไม่มีโค้ดในของที่ส่งมอบจริงเรียกฟังก์ชันนี้จากที่อื่นเลย — การเรียกครั้งที่สองจะทิ้ง ring ใน RAM ไปโดยไม่ได้เขียนลงจริง (flush) ก่อน
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
call site เดียวที่มีอยู่จริงในของที่ส่งมอบ
static void bentoclaw_ensure_init(void) {
if (s_module_inited) return;
/* Set per-tool rate limits from registry */
for (size_t i = 0; i < TOOL_COUNT; i++) {
if (s_tools[i].rate_per_min > 0) {
claw_rate_set(s_tools[i].name, s_tools[i].rate_per_min);
}
}
s_module_inited = true;
}

◆ claw_session_add()

bool claw_session_add ( claw_role_t role,
const char * content )

ผนวกข้อความหนึ่งรายการและตัด ring ให้เหลือเท่ากับ CLAW_SESSION_MAX_MSGS

ข้อกำหนดการเรียกใช้
ผนวกข้อความหนึ่งรายการและตัด ring ให้เหลือเท่ากับ CLAW_SESSION_MAX_MSGS; content ต้องปิดท้ายด้วย NUL และจะถูกตัดให้ยาวไม่เกิน CLAW_MSG_MAX_LEN (256) claw_session_init() ต้องทำงานมาก่อน (ผ่าน bentoclaw_ensure_init()) role ที่โค้ดในของที่ส่งมอบจริงใช้: CLAW_ROLE_USER, CLAW_ROLE_ASSISTANT, CLAW_ROLE_SYSTEM (ตอนเชื่อมต่อและตอนตัดการเชื่อมต่อ) และ CLAW_ROLE_TOOL (ผลลัพธ์ของ tool) ลำดับบนเส้นทาง ask() เป็นไปโดยเจตนา: รอบสนทนาฝั่งผู้ใช้ถูกเพิ่มก่อนที่จะประกอบคำขอ และ รอบสนทนาฝั่ง assistant จะถูกผนวกหลัง claw_cb_success() เท่านั้น — คำขอที่ล้มเหลวจึงไม่เหลือรายการฝั่ง assistant ไว้เลย ค่าที่คืนมาเป็น bool ถูกทิ้งไปที่จุดเรียกทุกจุดในของที่ส่งมอบจริง ไม่มีการจับ lock — มี MicroPython task เพียง task เดียว
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
รอบสนทนาฝั่งผู้ใช้ ที่ถูกเพิ่มก่อนประกอบคำขอ:
/* ...context: inside bentoclaw_ask() ... */
/* Add user message to session */

รอบสนทนาฝั่ง assistant หลังจาก breaker บันทึกผลสำเร็จแล้ว:

/* ...context: inside bentoclaw_ask(), success path ... */
s_agent_state = CLAW_STATE_IDLE;
snprintf(s_last_result, sizeof(s_last_result), "ok (%d bytes)", resp_len);
claw_ipc_send_ui(CLAW_UI_LAST_RESULT, s_last_result, strlen(s_last_result));
claw_ipc_send_ui(CLAW_UI_STATUS_TEXT, "Online (HTTPS)", 14);
/* Add assistant response to session (s_work_small holds response) */
return mp_obj_new_str(s_work_small, (size_t)resp_len);

◆ claw_session_count()

uint16_t claw_session_count ( void )

จำนวนข้อความที่อยู่ใน ring ขณะนั้น

ข้อกำหนดการเรียกใช้
จำนวนข้อความที่อยู่ใน ring ขณะนั้น (0 ถึง CLAW_SESSION_MAX_MSGS) เป็นส่วนที่ใช้อ่านสถานะ เปิดออกไปเป็นคีย์ session_msgs ของ bentoclaw.status() และอยู่ในคำตอบ TACP STATUS ด้วย เป็นการอ่านอย่างเดียว; ไม่มีการจับ lock; ทำงานใน MicroPython task context; bentoclaw_ensure_init() ทำงานมาก่อนหน้าแล้ว
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
อยู่ภายใน bentoclaw_status()
/* ...context: inside bentoclaw_status() ... */
mp_obj_dict_store(MP_OBJ_FROM_PTR(d),
MP_OBJ_NEW_QSTR(MP_QSTR_session_msgs),
mp_obj_new_int(claw_session_count()));

◆ claw_session_clear()

void claw_session_clear ( void )

ลบ /.bentoclaw_session และล้าง ring ให้ว่าง; ที่เก็บ memory ไม่ถูกแตะ

ข้อกำหนดการเรียกใช้
ลบ /.bentoclaw_session และล้าง ring ให้ว่าง; /.bentoclaw_memory ไม่ถูกแตะ ผู้ใช้ไลบรารีในของที่ส่งมอบจริงจับคู่ฟังก์ชันนี้กับข้อความ IPC CLAW_UI_CLEAR เพื่อให้แผงสนทนาบน CM55 ถูกล้างในขั้นเดียวกัน — guard บน claw_ipc_initialized คือสิ่งที่ทำให้การจับคู่นี้ปลอดภัยก่อนที่ลิงก์ IPC จะพร้อม ต้องเรียก bentoclaw_ensure_init() มาก่อน; เป็น void; ทำงานใน MicroPython task context (ลบไฟล์ผ่าน VFS bridge)
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
การล้างเซสชันและล้าง UI ที่จับคู่กัน
static mp_obj_t bentoclaw_session_clear(void) {
bentoclaw_ensure_init();
if (claw_ipc_initialized) {
claw_ipc_send_ui(CLAW_UI_CLEAR, "", 0);
}
return mp_const_none;
}

◆ claw_session_build_context()

size_t claw_session_build_context ( char * out_buf,
size_t out_max )

เรนเดอร์รอบสนทนาล่าสุดพร้อม memory ลงในบัฟเฟอร์ที่ผู้เรียกจัดหามาให้; ยังไม่ผ่านการ escape แบบ JSON

ข้อกำหนดการเรียกใช้
เรนเดอร์รอบสนทนาล่าสุดของเซสชันพร้อมกับ memory ที่คงอยู่ถาวร ออกมาเป็นสตริงบริบทของ prompt ผู้เรียกเป็นฝ่ายจัดหาบัฟเฟอร์ — ตัวแปร static ที่ใช้ร่วมกันของโมดูลในของที่ส่งมอบจริงคือ s_work_large[3072] และ s_work_small[512] — และการเรียกจริงส่งค่า sizeof(s_work_large) - 256 เข้าไป ซึ่งเป็นการกันพื้นที่เผื่อไว้ 256 ไบต์โดยเจตนา คืนค่าเป็นจำนวนไบต์ที่เขียนได้ ผลลัพธ์ ยังไม่ผ่านการ escape แบบ JSON: ต้องส่งผ่าน json_escape ก่อนเข้าไปอยู่ในเนื้อคำขอ ตรงตามที่ตัวอย่างอ้างอิงทำไว้ทุกประการ เป้าหมายของการ escape กับบัฟเฟอร์ที่ใช้ประกอบ JSON ไม่ทับซ้อนกันเลย (บริบทอยู่ใน s_work_large ส่วนที่ escape แล้วอยู่ใน s_work_small แล้วจึงประกอบ JSON กลับลงใน s_work_large หลังจากใช้บริบทเสร็จแล้ว) ยังมีรูปแบบที่ง่ายกว่านี้ในของที่ส่งมอบจริงซึ่งส่งขนาดบัฟเฟอร์เต็มเข้าไป ต้องเรียก claw_session_init() มาก่อน; ทำงานใน MicroPython task context; ไม่มีการจับ lock
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
ประกอบบริบท, escape, แล้วประกอบ JSON พร้อมการกันพื้นที่เผื่อและวินัยเรื่องบัฟเฟอร์ที่ไม่ทับซ้อนกัน
/* ...context: inside bentoclaw_ask() ... */
/* Build context → escape both → build JSON → POST.
* Escape prompt+context into s_work_small halves, then build JSON
* in s_work_large (no overlap). */
/* 1) Build context string in s_work_large */
size_t ctx_len = claw_session_build_context(s_work_large, sizeof(s_work_large) - 256);
/* 2) Escape prompt into s_work_small first half */
char *esc_p = s_work_small;
size_t ep_max = sizeof(s_work_small) / 2;
size_t ep_len = json_escape(esc_p, ep_max, prompt,
prompt_len > 200 ? 200 : prompt_len);
/* 3) Escape context into s_work_small second half */
char *esc_c = s_work_small + ep_max;
size_t ec_max = sizeof(s_work_small) / 2;
size_t ec_len = json_escape(esc_c, ec_max,
s_work_large, ctx_len > 200 ? 200 : ctx_len);
/* ...context: inside bentoclaw_ask() ... */
/* 4) Build JSON in s_work_large (no overlap with s_work_small) */
int json_len = snprintf(s_work_large, sizeof(s_work_large),
"{\"prompt\":\"%.*s\",\"context\":\"%.*s\"}",
(int)ep_len, esc_p, (int)ec_len, esc_c);

◆ claw_memory_set()

bool claw_memory_set ( const char * key,
const char * value )

เก็บคู่คีย์/ค่าแบบถาวรที่อยู่รอดทั้งการล้างเซสชันและ soft reset

ข้อกำหนดการเรียกใช้
เก็บคู่คีย์/ค่าแบบถาวรไว้ใน /.bentoclaw_memory; key ยาวไม่เกิน CLAW_MEM_KEY_MAX (32) ตัวอักษร และ value ยาวไม่เกิน CLAW_MEM_VAL_MAX (128) คืนค่า true เมื่อสำเร็จ และคืน false เมื่อที่เก็บเต็มหรือเขียนไม่ได้ — handler ของ TACP REMEMBER แปลงค่า bool นั้นเป็นคำตอบ "ok" / "full" โดยตรง เป็นส่วนหนึ่งของสถานะถาวรของระบบย่อยความปลอดภัย เคียงกับกลุ่มฟังก์ชัน trust/rate: มันอยู่รอดทั้ง claw_session_clear() และ soft reset ต้องเรียก bentoclaw_ensure_init() มาก่อน; ทำงานใน MicroPython task context; ไม่มีการจับ lock
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง
binding ของ bentoclaw.remember() ซึ่งเป็นตัวอย่างอ้างอิงหลัก
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);
bool ok = claw_memory_set(key, val);
return mp_obj_new_bool(ok);
}

◆ claw_memory_get()

bool claw_memory_get ( const char * key,
char * out_value,
size_t out_max )

ค้นหาคีย์ใน /.bentoclaw_memory; คืน false เมื่อไม่พบ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

ข้อกำหนดการเรียกใช้
ค้นหา key ใน /.bentoclaw_memory แล้วคัดลอกค่าไปไว้ที่ out_value (ให้จองบัฟเฟอร์ขนาด CLAW_MEM_VAL_MAX) คืนค่า true เมื่อพบ และคืน false เมื่อไม่พบหรืออ่านที่เก็บไม่ได้ — ไม่ใช่ข้อผิดพลาดที่ถึงขั้นต้อง raise ให้ย้อนไปใช้ค่าเริ่มต้นแทน claw_session_init() ต้องทำงานมาก่อน; ทำงานใน MicroPython task context (อ่านไฟล์ผ่าน VFS bridge); ไม่มีการจับ lock ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ — ทั้งในเทมเพลตและในทรีที่ถูก archive ไว้; ตัวนิยาม (claw_session.c) เข้าถึงได้ผ่าน archive เท่านั้น
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง (เขียนขึ้นเอง — ไม่มี call site ในของที่ส่งมอบจริง)
static void bento_ex_claw_memory_get(void)
{
char value[CLAW_MEM_VAL_MAX];
/* false = key absent (or store unreadable) — not an error path worth
* raising over; fall back to the default. */
if (!claw_memory_get("user_name", value, sizeof(value))) {
(void)strncpy(value, "friend", sizeof(value) - 1u);
value[sizeof(value) - 1u] = '\0';
}
(void)value;
}

◆ claw_session_dirty()

bool claw_session_dirty ( void )

predicate ที่ต้นทุนต่ำ: ring ใน RAM มีการเปลี่ยนแปลงที่ยังไม่ได้เขียนลงจริงหรือไม่ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

ข้อกำหนดการเรียกใช้
predicate ที่ต้นทุนต่ำและไม่มี I/O: คืนค่า true เมื่อ ring ใน RAM ยังมีการเปลี่ยนแปลงที่ยังไม่ได้เขียนลงจริง (flush) ลงหน่วยความจำแฟลช มีไว้เพื่อใช้ตัดสินว่าคุ้มที่จะ flush ในจังหวะที่ว่างหรือไม่ ตามแนวเดียวกับสำนวน wifi_creds_flush_if_dirty() ในของที่ส่งมอบจริง (lfs_wifi_creds_write()) ทำงานใน MicroPython task context; ไม่มีการจับ lock ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ ที่ใดเลย
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง (เขียนขึ้นเอง — ไม่มี call site ในของที่ส่งมอบจริง)
static bool bento_ex_claw_session_dirty(void)
{
/* Nothing to do while clean — skip the flash write entirely. */
}

◆ claw_session_flush()

bool claw_session_flush ( void )

เขียน ring ที่ยังค้างอยู่ลงหน่วยความจำแฟลช จาก MicroPython task context เท่านั้น ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ

ข้อกำหนดการเรียกใช้
เขียน ring ที่ยังค้างอยู่ลงไฟล์ /.bentoclaw_session บน QSPI ต้องเรียกจาก MicroPython task context (เป็นข้อกำหนดใน header — การเขียนทำโดยรัน open() ของ Python) คืนค่า true เมื่อสำเร็จ; เมื่อล้มเหลว เซสชันจะยังคงค้างอยู่เพื่อให้การเรียกครั้งถัดไปลองใหม่ — ห้ามล้างสถานะรอบ ๆ การเขียนแฟลชที่ล้มเหลว การเขียนหน่วยความจำแฟลชกินเวลาระดับมิลลิวินาที: ให้เรียกในจังหวะที่ว่าง ไม่ใช่เรียกทุกข้อความ ไม่มีผู้เรียกที่มีอยู่จริงในของที่ส่งมอบ ที่ใดเลย
variant ที่ใช้ได้
mtb-mpy เท่านั้น (ไม่มีการลิงก์ libbento_mpy.a เมื่อ BENTO_HAS_MPY=0)
ตัวอย่าง (เขียนขึ้นเอง — ไม่มี call site ในของที่ส่งมอบจริง)
static void bento_ex_claw_session_flush(void)
{
return; /* nothing pending */
}
/* Failed write: the session stays dirty — the next idle-point
* call retries. Do not clear anything here. */
return;
}
}