- หน้าแรก
- Documentation
- เซสชัน
- นโยบายการลองใหม่อัตโนมัติแบบไม่บีบอัด
นโยบายการลองใหม่อัตโนมัติแบบไม่บีบอัด
เอกสารนี้อธิบายเส้นทางการลองใหม่เมื่อเกิดข้อผิดพลาด API มาตรฐานใน AgentSession
โดยไม่ครอบคลุมการกู้คืนเมื่อบริบทล้นผ่านการบีบอัดอัตโนมัติ การล้นบริบทจะถูกจัดการด้วยลอจิกการบีบอัดและมีเอกสารแยกต่างหากใน compaction.md
ไฟล์การดำเนินการ
หัวข้อที่มีชื่อว่า “ไฟล์การดำเนินการ”../src/session/agent-session.ts../src/config/settings-schema.ts../src/modes/controllers/event-controller.ts../src/modes/rpc/rpc-mode.ts../src/modes/rpc/rpc-client.ts../src/modes/rpc/rpc-types.ts
ขอบเขตและความแตกต่างจากการบีบอัด
หัวข้อที่มีชื่อว่า “ขอบเขตและความแตกต่างจากการบีบอัด”การลองใหม่และการบีบอัดถูกตรวจสอบจากเส้นทาง agent_end เดียวกัน แต่ถูกแยกออกจากกันโดยตั้งใจ:
agent_endตรวจสอบข้อความของ assistant ล่าสุด#isRetryableError(...)ทำงานก่อน- หากเริ่มการลองใหม่ การตรวจสอบการบีบอัดจะถูกข้ามสำหรับรอบนั้น
- ข้อผิดพลาดที่บริบทล้นถูกยกเว้นอย่างเด็ดขาดจากการจำแนกประเภทการลองใหม่ (
isContextOverflow(...)ตัดวงจรการลองใหม่) - การล้นบริบทจึงตกไปยัง
#checkCompaction(...)แทนที่จะเป็นการลองใหม่มาตรฐาน
สรุป: ความล้มเหลวประเภทโหลดเกิน/อัตรา/เซิร์ฟเวอร์/เครือข่ายใช้นโยบายการลองใหม่นี้ ส่วนการล้นหน้าต่างบริบทใช้การกู้คืนด้วยการบีบอัด
การจำแนกประเภทการลองใหม่
หัวข้อที่มีชื่อว่า “การจำแนกประเภทการลองใหม่”#isRetryableError(...) ต้องการเงื่อนไขทั้งหมดต่อไปนี้:
- assistant
stopReason === "error" - มี
errorMessageอยู่ - ข้อความไม่ใช่การล้นบริบท
errorMessageตรงกับ#isRetryableErrorMessage(...)
ชุดรูปแบบที่ลองใหม่ได้ในปัจจุบัน (ใช้ regex):
- overloaded
- rate limit / usage limit / too many requests
- คลาสเซิร์ฟเวอร์คล้าย HTTP: 429, 500, 502, 503, 504
- service unavailable / server error / internal error
- connection error / fetch failed
- คำว่า
retry delay
การจำแนกประเภทนี้ใช้การจับคู่รูปแบบสตริง ไม่ใช่โค้ดข้อผิดพลาดของผู้ให้บริการแบบมีโครงสร้าง
วงจรชีวิตการลองใหม่และการเปลี่ยนสถานะ
หัวข้อที่มีชื่อว่า “วงจรชีวิตการลองใหม่และการเปลี่ยนสถานะ”สถานะ session ที่ใช้โดยการลองใหม่:
#retryAttempt: number(0หมายถึงไม่ได้ทำงาน)#retryPromise: Promise<void> | undefined(ติดตามวงจรชีวิตการลองใหม่ที่กำลังดำเนินการ)#retryResolve: (() => void) | undefined(แก้ไข#retryPromise)#retryAbortController: AbortController | undefined(ยกเลิกการรอ backoff)
ขั้นตอน (#handleRetryableError):
- อ่านกลุ่มการตั้งค่า
retry - ถ้า
retry.enabled === falseหยุดทันที (falseไม่เริ่มการลองใหม่) - เพิ่มค่า
#retryAttempt - สร้าง
#retryPromiseครั้งเดียว (ครั้งแรกในห่วงโซ่) - ถ้าความพยายามเกิน
retry.maxRetriesส่งเหตุการณ์ความล้มเหลวสุดท้ายและหยุด - คำนวณหน่วงเวลา:
retry.baseDelayMs * 2^(attempt-1) - สำหรับข้อผิดพลาดขีดจำกัดการใช้งาน แยกวิเคราะห์คำใบ้การลองใหม่และเรียก auth storage (
markUsageLimitReached(...)); ถ้าการสลับผู้ให้บริการ/โมเดลสำเร็จ บังคับหน่วงเวลาเป็น0 - ส่ง
auto_retry_start - ลบข้อความผิดพลาดของ assistant ท้ายสุดออกจากสถานะรันไทม์ของ agent (เก็บไว้ในประวัติ session ที่บันทึกแล้ว)
- รอโดยมีการรองรับการยกเลิก
- เมื่อตื่น กำหนดเวลา
agent.continue()ผ่านsetTimeout(..., 0)
สิ่งที่รีเซ็ตตัวนับการลองใหม่
หัวข้อที่มีชื่อว่า “สิ่งที่รีเซ็ตตัวนับการลองใหม่”#retryAttempt รีเซ็ตเป็น 0 ในกรณีเหล่านี้:
- ข้อความของ assistant ที่สำเร็จแบบไม่มีข้อผิดพลาดและไม่ถูกยกเลิกครั้งแรกหลังจากเริ่มการลองใหม่ (ส่ง
auto_retry_end { success: true }) - การยกเลิกการลองใหม่ระหว่างการรอ backoff
- เส้นทางที่เกินจำนวนการลองใหม่สูงสุด
#retryPromise แก้ไข/ล้างเมื่อห่วงโซ่การลองใหม่สิ้นสุด (สำเร็จ ยกเลิก หรือเกินสูงสุด) ผ่าน #resolveRetry()
ความหมายของ Backoff และจำนวนความพยายามสูงสุด
หัวข้อที่มีชื่อว่า “ความหมายของ Backoff และจำนวนความพยายามสูงสุด”การตั้งค่า:
retry.enabled(ค่าเริ่มต้นtrue)retry.maxRetries(ค่าเริ่มต้น3)retry.baseDelayMs(ค่าเริ่มต้น2000)
การนับความพยายาม:
- ตัวนับความพยายามถูกเพิ่มก่อนการตรวจสอบค่าสูงสุด
- เหตุการณ์เริ่มต้นใช้ความพยายามปัจจุบัน (เริ่มจาก 1)
- เหตุการณ์สิ้นสุดที่เกินสูงสุดรายงาน
attempt: this.#retryAttempt - 1(จำนวนการลองใหม่ครั้งสุดท้าย)
ลำดับ backoff ด้วยการตั้งค่าเริ่มต้น:
- ความพยายามที่ 1: 2000 มิลลิวินาที
- ความพยายามที่ 2: 4000 มิลลิวินาที
- ความพยายามที่ 3: 8000 มิลลิวินาที
อินพุตการแทนที่หน่วงเวลาถูกใช้เฉพาะในเส้นทางการจัดการขีดจำกัดการใช้งาน และเพื่อมีอิทธิพลต่อการตัดสินใจสลับโมเดล/บัญชีของ auth storage เท่านั้น ในเส้นทางการลองใหม่แบบไม่บีบอัดหลัก backoff ยังคงเป็นการหน่วงเวลาแบบเอกซ์โพเนนเชียลเฉพาะที่ เว้นแต่การสลับสำเร็จ (delayMs = 0)
กลไกการยกเลิก
หัวข้อที่มีชื่อว่า “กลไกการยกเลิก”การยกเลิกการลองใหม่อย่างชัดเจน
หัวข้อที่มีชื่อว่า “การยกเลิกการลองใหม่อย่างชัดเจน”abortRetry():
- ยกเลิก
#retryAbortController(ถ้ามี) - แก้ไข promise การลองใหม่ (
#resolveRetry()) เพื่อปลดบล็อกผู้ที่รออยู่
ถ้าการยกเลิกเกิดขึ้นระหว่างการรอ เส้นทาง catch จะส่ง:
auto_retry_end { success: false, finalError: "Retry cancelled" }- รีเซ็ต attempt/controller
การโต้ตอบกับการยกเลิกการทำงานทั่วไป
หัวข้อที่มีชื่อว่า “การโต้ตอบกับการยกเลิกการทำงานทั่วไป”abort() เรียก abortRetry() ก่อนที่จะยกเลิก stream ของ agent ที่ทำงานอยู่ ซึ่งรับประกันว่า backoff การลองใหม่จะถูกยกเลิกเมื่อผู้ใช้สั่งยกเลิกทั่วไป
การโต้ตอบกับ TUI
หัวข้อที่มีชื่อว่า “การโต้ตอบกับ TUI”เมื่อ auto_retry_start, EventController:
- สลับตัวจัดการ
Escเป็นsession.abortRetry() - แสดงข้อความ loader:
Retrying (attempt/maxAttempts) in Ns… (esc to cancel)
เมื่อ auto_retry_end จะคืนค่าตัวจัดการ Esc ก่อนหน้าและล้างสถานะ loader
พฤติกรรมการสตรีมมิงและการเสร็จสิ้นพรอมต์
หัวข้อที่มีชื่อว่า “พฤติกรรมการสตรีมมิงและการเสร็จสิ้นพรอมต์”prompt() สุดท้ายรอที่ #waitForRetry() หลังจาก agent.prompt(...) ส่งคืน
ผลลัพธ์:
- การเรียก prompt จะไม่แก้ไขอย่างสมบูรณ์จนกว่าห่วงโซ่การลองใหม่ที่เริ่มแล้วจะสิ้นสุด (สำเร็จ/ล้มเหลว/ยกเลิก)
- วงจรชีวิตการลองใหม่เป็นส่วนหนึ่งของขอบเขตการดำเนินการ prompt เชิงตรรกะเดียว
สิ่งนี้ป้องกันผู้เรียกจากการถือว่ารอบที่กำลังลองใหม่เสร็จสิ้นก่อนเวลาอันควร
การควบคุม: การตั้งค่าและ RPC
หัวข้อที่มีชื่อว่า “การควบคุม: การตั้งค่าและ RPC”ปุ่มการกำหนดค่า
หัวข้อที่มีชื่อว่า “ปุ่มการกำหนดค่า”กำหนดในสคีมาการตั้งค่าภายใต้กลุ่ม retry:
retry.enabledretry.maxRetriesretry.baseDelayMs
การสลับแบบโปรแกรมใน session:
setAutoRetryEnabled(enabled)เขียนretry.enabledautoRetryEnabledอ่านretry.enabledisRetryingรายงานว่า promise วงจรชีวิตการลองใหม่กำลังทำงานอยู่หรือไม่
การควบคุม RPC
หัวข้อที่มีชื่อว่า “การควบคุม RPC”พื้นผิวคำสั่ง RPC:
set_auto_retry→session.setAutoRetryEnabled(command.enabled)abort_retry→session.abortRetry()
ตัวช่วย client:
RpcClient.setAutoRetry(enabled)RpcClient.abortRetry()
ทั้งสองคำสั่งส่งคืนการตอบสนองสำเร็จ รายละเอียดความคืบหน้า/ความล้มเหลวของการลองใหม่มาจากเหตุการณ์ session แบบ stream ไม่ใช่จาก payload การตอบสนองคำสั่ง
การส่งเหตุการณ์และการแสดงผลความล้มเหลว
หัวข้อที่มีชื่อว่า “การส่งเหตุการณ์และการแสดงผลความล้มเหลว”เหตุการณ์การลองใหม่ระดับ session:
auto_retry_start { attempt, maxAttempts, delayMs, errorMessage }auto_retry_end { success, attempt, finalError? }
การแพร่กระจาย:
- ส่งผ่าน
AgentSession.subscribe(...) - ส่งต่อไปยัง extension runner เป็น extension events
- ในโหมด RPC ส่งต่อโดยตรงเป็น JSON event objects (
session.subscribe(event => output(event))) - ใน TUI ถูกใช้งานโดย
EventControllerสำหรับ UI loader/error
การแสดงผลความล้มเหลวสุดท้าย:
- เมื่อเกินสูงสุดหรือยกเลิก
auto_retry_end.success === false - TUI แสดง:
Retry failed after N attempts: <finalError> - Extensions/hooks ได้รับ
auto_retry_endด้วยฟิลด์เดียวกัน - ผู้บริโภค RPC ได้รับ event object เดียวกันบน stdout stream
เงื่อนไขการหยุดถาวร
หัวข้อที่มีชื่อว่า “เงื่อนไขการหยุดถาวร”การลองใหม่จะหยุดและไม่ดำเนินการต่ออัตโนมัติเมื่อเกิดเหตุการณ์ใดๆ เหล่านี้:
retry.enabledเป็น false- ข้อผิดพลาดไม่ถูกจำแนกประเภทเป็นการลองใหม่ได้
- ข้อผิดพลาดคือการล้นบริบท (ส่งต่อไปยังเส้นทางการบีบอัด)
- เกินจำนวนการลองใหม่สูงสุด
- ผู้ใช้ยกเลิกการลองใหม่ (
abort_retryหรือEscระหว่าง loader การลองใหม่) - การยกเลิกทั่วไป (
abort) ยกเลิกการลองใหม่ก่อน
ห่วงโซ่การลองใหม่ใหม่ยังคงสามารถเริ่มต้นได้ในภายหลังเมื่อเกิดข้อผิดพลาดที่ลองใหม่ได้ในอนาคตหลังจากตัวนับรีเซ็ต
ข้อควรระวังในการดำเนินงาน
หัวข้อที่มีชื่อว่า “ข้อควรระวังในการดำเนินงาน”- การจำแนกประเภทใช้การจับคู่ข้อความด้วย regex ไม่ใช้ข้อผิดพลาดที่มีโครงสร้างเฉพาะของผู้ให้บริการที่นี่
- การลองใหม่จะลบข้อผิดพลาดของ assistant ที่ล้มเหลวออกจากบริบทรันไทม์ก่อนดำเนินการต่อ แต่ประวัติ session ยังคงเก็บรายการข้อผิดพลาดนั้นไว้
RpcSessionStateในปัจจุบันเปิดเผยautoCompactionEnabledแต่ไม่มีฟิลด์autoRetryEnabledผู้เรียก RPC ต้องติดตามสถานะการสลับของตนเองหรือสอบถามการตั้งค่าผ่าน API อื่น