mockModel لكي تعمل كما تُلصَق، دون مفتاح API. ضع
provider أو model حقيقيًا للـ agent الخاص بك؛ ولا شيء آخر يتغيّر. كل
قسم يحيل إلى الصفحة التي فيها التفاصيل الكاملة.
1. أداة تحتاج موافقة
اضبطneedsApproval على الأداة. يتوقف الـ run قبل أن تُنفَّذ الأداة:
2. أعطِ الـ agent مخزنًا متينًا
الوقفات ونقاط الحفظ تعيش فيstore الخاص بالـ agent. الافتراضي في الذاكرة،
وتضيع محتوياته عند إعادة التشغيل. استخدم مخزنًا متينًا: SqliteStore (ملف واحد يدعم المعاملات،
تتشاركه عدة processes على جهاز واحد) أو fileStore(dir) (ملفات JSON عادية). راجع
اختيار المخزن.
3. الإرسال: يتوقف الـ run
لا ترميsend() خطأً عند الوقفة. بل تُرجع النتيجة مع
finishReason: 'awaiting-approval' والـ id المطلوب اتخاذ القرار بشأنه:
agent.session({ id }) بدل sessionId عندما يجب أن تحتفظ المحادثة
بسجلّ عبر الدورات (راجع الجلسات)؛
استدعاءات الإيقاف والاستئناف أدناه هي نفسها.
4. في process جديد: اسرد الوقفات واتّخذ القرار في إحداها
شغّل الـ process مرة أخرى بالمخزن نفسه. تُرجعagent.approvals.list()
الاستدعاءات المعلّقة، الأقدم أولًا، بما فيها التي تركها في المخزن process آخر أو run
سابق. وتنفّذ agent.approvals.resolve() الاستدعاء (أو ترفضه)،
وتكمل الـ run، وتُرجع النتيجة:
- للرفض، مرّر
approved: falseوnoteيراه النموذج سببًا للرفض. - الجلسة التي توقفت يُعثَر عليها من سجلّ وقفتها، فلا تحتاج إلى
فتحها أو استدعاء
resume()أولًا. - ترمي
resolve()خطأً عندما يكون الـ id غير معروف أو حُسم مسبقًا، فإذا تسابق processان على وقفة واحدة، لا يستطيعان كلاهما تشغيل الأداة. - الوقفة الناتجة من
send(msg, { sessionId })تظهر فيagent.pending()معstatus: 'awaiting-approval'وapprovalIdالخاص بها.
5. شاهد الـ run ينتهي
تُرجعresolve() نتيجة الـ run المُكمَل. نُفّذت الأداة، وحصل النموذج على
مخرجاتها وأجاب، وfinishReason هو 'stop'. إذا توقف الـ run المُكمَل
مرة أخرى (استدعاء آخر عليه needsApproval)، تحصل على 'awaiting-approval'
وid جديد: اسرد واتّخذ القرار من جديد. ولعرض التقدّم للمستخدم بدلًا من ذلك، استخدم
agent.approvals.streamResolve(). كل ما عدا ذلك بشأن القرارات (عدة استدعاءات
في خطوة واحدة، و”لا تسأل مرة أخرى”، والموافقة مع وسائط معدّلة، وانتهاء الصلاحية) موجود في
الموافقات.
6. حين يموت الـ process في منتصف الـ run
يترك الانهيار (crash) أو الإيقاف القسري نقطة حفظ الـ run في المخزن بالحالة'in-progress'. يعثر عليها الـ process المُعاد تشغيله بـ agent.pending() ويُنهيها
بـ agent.resume(sessionId)، أو يسلّم المهمة كلها إلى agent.recover().
يحاكي هذا المقتطف الانهيار بأداة ترمي
PropagatingToolError في المرة الأولى (كما يوقف process يموت
الخطوة)، ثم يتعافى:
agent.recover() مرة واحدة لكل process عند
بدء التشغيل: فهي تستطلع pending() وتستأنف كل run بحالة 'in-progress'، وتترك
الموافقات لإنسان، وتشغيلها آمن على كل نسخة (replica) (تضمن run leases أن
process واحدًا فقط يستأنف كل run). راجع
الاستعادة التلقائية.
مرة واحدة على الأقل (at-least-once) للخطوة التي كانت تعمل. ردود النموذج المسجّلة
ونتائج الأدوات المنتهية لا تتكرر أبدًا: ولهذا نُفّذت charge مرة واحدة أعلاه.
لكن الأداة التي كانت في منتصف الاستدعاء حين مات الـ process تُنفَّذ من جديد عند الاستئناف، فقد
يحدث أثرها الجانبي مرتين. اجعل هذه الأدوات idempotent (مفتاح idempotency
يُمرَّر إلى API الدفع، أو فحص “هل فعلت هذا من قبل”). راجع
At-least-once tools.
والأداة التي عليها needsApproval لا تتأثر بهذا وهي تنتظر: فالوقفة
لا تسجّل أي عمل، بل تنتظر القرار فقط.
7. عبر HTTP
الخادم المبني (راجع النشر) يفعل هذا نيابةً عنك. العميل الذي يعيد إرسالPOST /chat بعد انقطاع الاتصال يستطيع إرسال ترويسة
Idempotency-Key نفسها: الدورة المنتهية تُعاد دون تشغيل أي شيء،
والدورة التي قطعها انهيار تُستأنف من آخر نقطة حفظ لها بدل
البدء من جديد. الجلسة المتوقفة على موافقة تُجيب بـ 409
(LOUSHO_SESSION_AWAITING_APPROVAL) حتى يُتّخذ القرار. جدول النتائج
موجود في إعادة إرسال دورة.
إلى أين بعد ذلك
- الموافقات: سياسات الصلاحيات، وعدة استدعاءات في خطوة واحدة، وانتهاء الصلاحية، واتخاذ القرار في الكود.
- الجلسات: دورات الجلسات المتينة والمخازن.
- التنفيذ المتين: نقاط الحفظ، وrun leases، والضمانات، والـ fork والـ replay.