Skip to main content
يضع 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: وأي سطر ليس حدثًا معروفًا، ولذلك تقرأ صيغتَي التأطير كلتيهما. والخروج من حلقتها يلغي جسم الاستجابة.