useLoushoAgent() وكيلًا خلف واجهة محادثة. فهو يشغّل دورة، ويقرأ بث الأحداث ذا الأنواع المحدّدة فور وصوله، ويحوّله إلى حالة جاهزة للعرض: رسائل بنصوصها واستدعاءات أدواتها، وقيمة status لحقل كتابة الرسائل، واستدعاء الأداة الذي ينتظر الموافقة إن وُجد.
يوجد الخطّاف (hook) في المسار الفرعي @lousho/build-ai-agent/react. وreact (18 أو 19) اعتمادية نظيرة اختيارية: ثبّتها في التطبيق الذي يستخدم الخطّاف.
المصادر
يحدّد الوسيط الأول أين يعمل الوكيل.
وضع «داخل العملية» مخصّص لكود React الذي يعمل حيث يستطيع الوكيل أن يعمل (Electron، React Native، الاختبارات). أما في المتصفح فاستخدم الوضع البعيد: مكان مفاتيح API الخاصة بالنماذج هو الخادم.
الحالة المُرجَعة
إزالة المكوّن (unmount) تلغي الدورة الجارية. وأحداث تشغيل وكيل فرعي (وهي تحمل
subagent) لا تغيّر messages؛ اقرأها من lastEvent إن أردت عرضها.
الموافقات
عند استدعاء أداة تحملneedsApproval، يتوقف التشغيل بالحدث approval.requested. تصبح قيمة status هي 'awaiting-approval' ويحمل pendingApproval الاستدعاء. بعد ذلك:
- داخل العملية، تستدعي
approve(note?)وreject(note?)الدالةagent.approvals.resolve({ id, approved, note })(راجع الموافقات). يُلحَق نص التشغيل المتواصل برسالة المساعد وتعودstatusإلى'idle'، أو إلى'awaiting-approval'إذا توقف التشغيل مجددًا. - عن بُعد، مرّر
{ approvalsUrl }وسيطًا ثانيًا. يرسل الخطّاف{ "approved": true, "note": "..." }بطلب POST إلى${approvalsUrl}/${approvalId}ويعرض تتمة التشغيل مباشرة من بث SSE الذي تجيب به واجهة الجلسات البرمجية (الأحداث نفسها التي في دورة محادثة؛ والتوقف الثاني يصل على هيئةapproval.requested). والخادم الذي يجيب بدلًا من ذلك بـ JSON من نوعApprovalOutcome(كالخادم الوارد أدناه) يبقى يعمل. - عن بُعد دون
approvalsUrl، لا تفعلapprove()وreject()شيئًا. اعرضpendingApprovalواحسمه عبر واجهتك البرمجية الخاصة، ثم أرسل الدورة التالية بـsend().
askQuestion: true يستطيع أن يطرح سؤالًا على المستخدم (راجع طرح سؤال على المستخدم). يصل التوقف بالطريقة نفسها، مع pendingApproval.kind === 'question': اعرض pendingApproval.question.text وoptions الخاصة به، واستدعِ answer(text).
جانب الخادم
نقطة نهاية Node للوضع البعيد، مع مسار الموافقات:useLoushoAgent({ url: '/api/agent' }, { approvalsUrl: '/api/approvals' }). ولمحادثة متعددة الدورات، احتفظ على الخادم بـ agent.session({ id }) لكل محادثة واستدعِ session.stream() بدلًا من agent.stream().
داخل العملية
يقبل الخطّاف الوكيل نفسه أيضًا. وهذا استدعاؤه من خطّاف مخصّص:من دون React
الخطّاف مغلِّف رقيق. منطق الحالة هوreduceAgentEvents(state, event)، وهو مختزِل (reducer) نقي يعمل على أحداث AgentEvent وبضعة إجراءات محلية (ui.send، ui.decide، ui.resumed، ui.stopped، ui.error)، أما parseEventStream(response) فتقرأ الأحداث من استجابة fetch. كلاهما مصدَّر من المسار الفرعي نفسه، لبناء ربط مخصّص أو عميل لا يستخدم React:
parseEventStream() الأسطر الفارغة وتعليقات SSE وحقول event:/id: وأي سطر ليس حدثًا معروفًا، ولذلك تقرأ صيغتَي التأطير كلتيهما. والخروج من حلقتها يلغي جسم الاستجابة.