1. المهمة

أنت تائه في الفضاء الشاسع الصامت غير المحدّد. لقد شقّت نبضة شمسية هائلة طريقها عبر سفينتك من خلال صدع بُعدي، ما أدى إلى تقطُّع السبل بك في جزء من الكون لا يتضمّن أي خريطة نجمية.
بعد أيام من أعمال الإصلاح الشاقة، عاد أخيرًا صوت المحركات المألوف. أصبحت مركبتك الفضائية جاهزة للعمل. لقد تمكّنت حتى من إنشاء وصلة صاعدة بعيدة المدى إلى السفينة الأم. موعد المغادرة وشيك. يمكنك الآن العودة إلى المنزل.
ولكن بينما تستعد لتشغيل محرك الأقراص، يقطع إشارة استغاثة التشويش. ترصد أجهزة الاستشعار لديك إشارة استغاثة من كوكب يُعرف باسم "أوزيماندياس". يجد الناجون أنفسهم محاصرين على هذا الكوكب المحتضر، وقد تعطلت سفينتهم. مهمتك بالغة الأهمية: عليك إنقاذهم قبل أن ينهار الغلاف الجوي للكوكب.
وسيلتهم الوحيدة للهروب هي صاروخ قديم مهجور تم بناؤه باستخدام تكنولوجيا فضائية، وعلى الرغم من أنّه يعمل، إلا أنّ محرك الانتقال السريع الخاص به محطّم. لإنقاذ الناجين، عليك الاتصال عن بُعد بـ Volatile Workbench وتجميع محرك أقراص بديل يدويًا.
التحدي
ليس لديك أي خبرة في هذه التكنولوجيا الفضائية، وهي معروفة بأنّها هشة للغاية. يمكن أن يصبح المكوّن غير المستقر خطرًا إشعاعيًا في ثوانٍ. لديك محاولة واحدة لتشغيل Volatile Workbench. يواجه مساعدك الحالي المستند إلى الذكاء الاصطناعي صعوبة في معالجة البيانات المرئية والأدلّة الفنية في الوقت نفسه، ما يؤدي إلى تقديم تعليمات غير صحيحة وتجاهل تحذيرات المخاطر.
لتحقيق النجاح، يجب ترقية الذكاء الاصطناعي من كيان واحد إلى نظام متعدد الوكلاء تعاوني.
أهداف مهمتك:
يمكنك تجميع Warp Drive باتّباع التعليمات المتخصّصة في الوقت الفعلي من نظامك الجديد المتعدّد الوكلاء.

ما ستنشئه

- نظام ذكاء اصطناعي متعدد الوكلاء وثنائي الاتجاه وفي الوقت الفعلي، ويضم وكيل إرسال مركزيًا يدير تفاعل المستخدمين وينسّق مع الوكلاء المتخصصين.
- وكيل Architect يتصل بقاعدة بيانات Redis لاسترداد البيانات التخطيطية وعرضها
- ميزة "مراقبة السلامة" الاستباقية التي تستخدم أدوات البث لتحليل خلاصة فيديو مباشرة بحثًا عن المخاطر المرئية وإرسال تنبيهات في الوقت الفعلي
- واجهة أمامية مستندة إلى React توفّر واجهة مستخدم للتفاعل مع النظام، وبث الفيديو والصوت إلى وكلاء الخلفية
ما ستتعلمه
التكنولوجيا / المفهوم | الوصف |
Google Agent Development Kit (ADK) | ستستخدم "حزمة تطوير البرامج" لإنشاء الوكلاء واختبارهم وإدارتهم، والاستفادة من إطار عملها في التعامل مع الاتصالات في الوقت الفعلي ودمج الأدوات ودورة حياة الوكيل. |
البث ثنائي الاتجاه | ستنفّذ وكيلاً لبث البيانات في اتجاهين يتيح التواصل الطبيعي في اتجاهين مع تأخير منخفض، ما يتيح لكل من الإنسان والذكاء الاصطناعي مقاطعة المحادثة والرد في الوقت الفعلي. |
الأنظمة المتعددة الوكلاء | ستتعرّف على كيفية تصميم نظام ذكاء اصطناعي موزّع يفوّض فيه وكيل رئيسي المهام إلى وكلاء متخصصين، ما يتيح فصل الاهتمامات وبنية أكثر قابلية للتوسّع. |
بروتوكول Agent-to-Agent (A2A) | ستستخدم بروتوكول A2A لتفعيل التواصل بين "وكيل الإرسال" و"وكيل المصمم"، ما يتيح لهما التعرّف على إمكانات بعضهما البعض وتبادل البيانات. |
أدوات البث | عليك تنفيذ أداة بث تعمل كعملية في الخلفية، وتُحلّل باستمرار خلاصة فيديو لرصد التغييرات في الحالة (المخاطر) وتقديم النتائج بشكل استباقي. |
Google Cloud Run وMemorystore | ستنشر تطبيق الوكلاء المتعددين بالكامل في بيئة التشغيل الفعلي، وذلك باستخدام Cloud Run لاستضافة خدمات الوكلاء وMemorystore (Redis) كقاعدة بيانات دائمة. |
FastAPI وWebSockets | تم إنشاء الخلفية باستخدام FastAPI وWebSockets للتعامل مع الاتصالات العالية الأداء وفي الوقت الفعلي اللازمة لبث الصوت والفيديو وردود الوكيل. |
React Frontend | ستعمل على واجهة مستخدم أمامية مستندة إلى React تسجّل وسائط المستخدم (الصوت/الفيديو) وتبثّها وتعرض الردود في الوقت الفعلي من وكلاء الذكاء الاصطناعي. |
2. إعداد البيئة
الوصول إلى Cloud Shell
👉انقر على "تفعيل Cloud Shell" في أعلى "وحدة تحكّم Google Cloud" (رمز شكل الوحدة الطرفية في أعلى لوحة Cloud Shell)، 
👉انقر على الزر "فتح المحرّر" (يبدو كملف مفتوح مع قلم رصاص). سيؤدي ذلك إلى فتح "محرِّر Cloud Shell للرموز" في النافذة. سيظهر لك مستكشف الملفات على الجانب الأيمن. 
👉افتح المحطة الطرفية في بيئة التطوير المتكاملة المستندة إلى السحابة الإلكترونية،

👉💻 في نافذة الأوامر، تأكَّد من أنّك قد أثبتّ ملكيتك وأنّ المشروع مضبوط على رقم تعريف مشروعك باستخدام الأمر التالي:
gcloud auth list
من المفترض أن يظهر حسابك على أنّه (ACTIVE).
المتطلبات الأساسية
ℹ️ المستوى 0 اختياري (ولكن يُنصح به)
يمكنك إكمال هذه المهمة بدون المستوى 0، ولكن إكمالها أولاً يوفّر لك تجربة أكثر تفاعلية، ما يتيح لك رؤية ضوء جهاز التتبّع يضيء على الخريطة العالمية أثناء تقدّمك.
إعداد بيئة المشروع
ارجع إلى نافذة الوحدة الطرفية، وأكمِل عملية الإعداد من خلال ضبط المشروع النشط وتفعيل خدمات Google Cloud المطلوبة (مثل Cloud Run وVertex AI وما إلى ذلك).
👉💻 في نافذة Terminal، اضبط رقم تعريف المشروع:
gcloud config set project $(cat ~/project_id.txt) --quiet
👉💻 تفعيل الخدمات المطلوبة:
gcloud services enable compute.googleapis.com \
artifactregistry.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
iam.googleapis.com \
aiplatform.googleapis.com \
cloudresourcemanager.googleapis.com \
redis.googleapis.com \
vpcaccess.googleapis.com
تثبيت الحِزم التابعة
👉💻 انتقِل إلى المستوى 4 وثبِّت حِزم Python المطلوبة:
cd $HOME/way-back-home/level_4
uv sync
تشمل التبعيات الرئيسية ما يلي:
الحزمة | الغرض |
| إطار عمل ويب عالي الأداء لبث محتوى Satellite Station وSSE |
| مطلوب خادم ASGI لتشغيل تطبيق FastAPI |
| حزمة Agent Development Kit المستخدَمة لإنشاء Formation Agent |
| مكتبة بروتوكولات للتواصل الموحّد بين الوكلاء |
| تطبيق أصلي للوصول إلى نماذج Gemini |
| برنامج عميل Python للاتصال بـ "مستودع المخططات" (Memorystore) |
| إتاحة التواصل الثنائي الاتجاه في الوقت الفعلي |
| إدارة متغيرات البيئة وأسرار الإعدادات |
| التحقّق من صحة البيانات وإدارة الإعدادات |
التحقّق من الإعداد
قبل أن نبدأ في كتابة الرمز، لنحرص على أنّ جميع الأنظمة تعمل بشكل سليم. نفِّذ نص التحقّق من الصحة لتدقيق مشروع Google Cloud وواجهات برمجة التطبيقات وتبعيات Python.
👉💻 تشغيل نص التحقّق البرمجي:
cd $HOME/way-back-home/level_4/scripts
chmod +x verify_setup.sh
. verify_setup.sh
👀 ستظهر لك سلسلة من علامات الصح الخضراء (✅).
- إذا ظهرت علامات X حمراء (❌)، اتّبِع أوامر الإصلاح المقترَحة في الناتج (مثل
gcloud services enable ...أوpip install ...). - ملاحظة: يمكن تجاهل التحذير الأصفر بشأن
.envفي الوقت الحالي، وسننشئ هذا الملف في الخطوة التالية.
🚀 Verifying Mission Bravo (Level 4) Infrastructure... ✅ Google Cloud Project: xxxxxxx ✅ Cloud APIs: Active ✅ Python Environment: Ready 🎉 SYSTEMS ONLINE. READY FOR MISSION.
3- إنشاء Schematic Vault في Redis ووكيل ثنائي الاتجاه باستخدام ADK
لقد عثرت على مستودع المخططات الكوكبية الذي يحتوي على مخططات الصاروخ المهجور. لاسترداد هذه البيانات بدقة، يجب التفاعل مع واجهة الإدارة المخصّصة للمستودع: وكيل Architect.

توفير مستودع المخططات (Redis)
قبل أن يتمكّن Architect من مساعدتنا، يجب التأكّد من استضافة البيانات في بيئة آمنة وعالية التوفّر. سنستخدم Redis كمخزن بيانات سريع لمخططات الكائنات الفضائية. لتسهيل عملية التطوير، سننشئ مثيلاً محليًا من Redis، ولكن سيتم تقديم تعليمات حول كيفية النشر في بيئة إنتاج باستخدام Google Cloud Memorystore لاحقًا.
👉💻 نفِّذ الأوامر التالية في الوحدة الطرفية لتوفير مثيل Redis (قد يستغرق ذلك من دقيقتَين إلى 3 دقائق):
docker run -d --name ozymandias-vault -p 6379:6379 redis:8.6-rc1-alpine
👉💻 لتحميل البيانات الأولية، شغِّل ما يلي لإدخال Redis Shell:
docker exec -it ozymandias-vault redis-cli
(سيتغيّر طلبك إلى 127.0.0.1:6379)
👉💻 الصِق هذه الأوامر في الداخل:
RPUSH "HYPERION-X" "Warp Core" "Flux Pipe" "Ion Thruster"
RPUSH "NOVA-V" "Ion Thruster" "Warp Core" "Flux Pipe"
RPUSH "OMEGA-9" "Flux Pipe" "Ion Thruster" "Warp Core"
RPUSH "GEMINI-MK1" "Coolant Tank" "Servo" "Fuel Cell"
RPUSH "APOLLO-13" "Warp Core" "Coolant Tank" "Ion Thruster"
RPUSH "VORTEX-7" "Quantum Cell" "Graviton Coil" "Plasma Injector"
RPUSH "CHRONOS-ALPHA" "Shield Emitter" "Data Crystal" "Quantum Cell"
RPUSH "NEBULA-Z" "Plasma Injector" "Flux Pipe" "Graviton Coil"
RPUSH "PULSAR-B" "Data Crystal" "Servo" "Shield Emitter"
RPUSH "TITAN-PRIME" "Ion Thruster" "Quantum Cell" "Warp Core"
👉💻 اكتب exit للرجوع إلى نافذة shell العادية.
👉💻 للتأكّد من توفّر البيانات من خلال طلب سفينة معيّنة مباشرةً من جهازك، نفِّذ ما يلي:
# Check 'TITAN-PRIME'
docker exec ozymandias-vault redis-cli LRANGE "TITAN-PRIME" 0 -1
👀 هذا هو الناتج المتوقّع:
1) "Ion Thruster" 2) "Quantum Cell" 3) "Warp Core"
تنفيذ Architect Agent
وكيل المهندس المعماري هو وكيل متخصص مسؤول عن استرداد المخططات التخطيطية من مستودع Redis. تعمل هذه الخدمة كواجهة مخصّصة للبيانات، ما يضمن حصول "وكيل الإرسال" الرئيسي على معلومات دقيقة ومنظَّمة بدون الحاجة إلى معرفة منطق قاعدة البيانات الأساسية.

حزمة تطوير الوكلاء (ADK) من Google هي إطار عمل معياري يتيح إعداد الوكلاء المتعدّدين. تتعامل هذه المنصة مع طبقتَين أساسيتَين:
- دورة حياة الاتصال والجلسة: يتطلّب التفاعل مع واجهات برمجة التطبيقات في الوقت الفعلي إدارة معقّدة للبروتوكول، بما في ذلك التعامل مع عمليات تأكيد الاتصال والمصادقة وإشارات إبقاء الاتصال نشطًا.
- استدعاء الدوال: هذه هي "رحلة النموذج والرمز البرمجي والنموذج". عندما يقرّر النموذج اللغوي الكبير أنّه بحاجة إلى بيانات، يعرض طلبًا منظَّمًا لاستدعاء دالة. تعترض "حزمة تطوير التطبيقات" على هذا الطلب، وتنفّذ رمز Python البرمجي (
lookup_schematic_tool)، وتعيد النتيجة إلى سياق النموذج في غضون أجزاء من الثانية.
سننشئ الآن Architect. لا يمكن لهذا الوكيل الوصول إلى الكاميرا. وهي موجودة فقط لتلقّي "اسم محرك أقراص" وعرض "قائمة الأجزاء" من قاعدة البيانات.
👉💻 سنستخدم الأمر adk create. هذه أداة من "حزمة تطوير الوكلاء" (ADK) تنشئ تلقائيًا الرمز البرمجي النموذجي وبنية الملفات لوكيل جديد، ما يوفّر وقت الإعداد.
cd $HOME/way-back-home/level_4/backend/
uv run adk create architect_agent
إعداد "الوكيل"
ستطلق واجهة سطر الأوامر معالج إعداد تفاعليًا. استخدِم الردود التالية لإعداد الوكيل:
- اختيار نموذج: انقر على الخيار 1 (Gemini Flash).
- ملاحظة: قد يختلف الإصدار المحدّد (مثل 2.5 أو 3.0) حسب مدى توفّره. اختَر دائمًا صيغة "Flash" للحصول على سرعة أكبر.
- اختيار نظام الخلفية: اختَر الخيار 2 (Vertex AI).
- إدخال رقم تعريف مشروع Google Cloud: اضغط على Enter لقبول القيمة التلقائية (التي تم رصدها من بيئتك).
- أدخِل منطقة Google Cloud: اضغط على Enter لقبول القيمة التلقائية (
us-central1).
👀 من المفترض أن يبدو تفاعلك مع الوحدة الطرفية على النحو التالي:
(way-back-home) user@cloudshell:~/way-back-home/level_4/agent$ adk create architect_agent Choose a model for the root agent: 1. gemini-2.5-flash 2. Other models (fill later) Choose model (1, 2): 1 1. Google AI 2. Vertex AI Choose a backend (1, 2): 2 You need an existing Google Cloud account and project... Enter Google Cloud project ID [your-project-id]: <PRESS ENTER> Enter Google Cloud region [us-central1]: <PRESS ENTER> Agent created in /home/user/way-back-home/level_4/agent/architect_agent: - .env - __init__.py - agent.py
من المفترض أن تظهر لك الآن رسالة Agent created تشير إلى نجاح العملية. يؤدي ذلك إلى إنشاء الرمز الأساسي الذي سنعدّله في الخطوة التالية.
👉✏️ انتقِل إلى ملف $HOME/way-back-home/level_4/backend/architect_agent/agent.py الذي تم إنشاؤه حديثًا وافتحه في المحرّر. أضِف مقتطف الأداة إلى الملف بعد سطر الاستيراد الأول:
import os
import redis
REDIS_IP = os.environ.get('REDIS_HOST', 'localhost')
r = redis.Redis(host=REDIS_IP, port=6379, decode_responses=True)
def lookup_schematic_tool(drive_name: str) -> list[str]:
"""Returns the ordered list of parts for a drive from local Redis."""
# Logic to clean input like "TARGET: X" -> "X"
clean_name = drive_name.replace("TARGET:", "").replace("TARGET", "").strip()
clean_name = clean_name.replace(":", "").strip()
# LRANGE gets all items in the list (index 0 to -1)
result = r.lrange(clean_name, 0, -1)
if not result:
print(f"[ARCHITECT] Error: Drive ID '{clean_name}' not found in Redis.")
return ["ERROR: Drive ID not found."]
print(f"[ARCHITECT] Returning schematic for {clean_name}: {result}")
return result
👉✏️ استبدِل سطر التعليمات بالكامل في تعريف root_agent بما يلي، وأضِف أيضًا الأداة التي حدّدناها سابقًا:
instruction='''SYSTEM ROLE: Database API.
INPUT: Text string (Drive Name).
TASK: Run `lookup_schematic_tool`.
OUTPUT: Return ONLY the raw list from the tool.
CONSTRAINT: Do NOT add conversational text.
''',
tools=[lookup_schematic_tool],
مزايا حزمة تطوير التطبيقات (ADK)
مع توفّر Architect على الإنترنت، أصبح لدينا الآن مصدر موثوق. قبل ربط هذا الوكيل بالوكيل الأساسي، تقدّم "حزمة تطوير الوكلاء" (ADK) ميزة كبيرة من خلال تبسيط تعقيدات إنشاء وكلاء الذكاء الاصطناعي واختبارهم. باستخدام adk web وحدة تحكّم المطوّرينadk web المضمّنة، يمكننا عزل وظائف Architect Agent والتحقّق منها، لا سيما إمكانات استدعاء الأدوات، قبل دمجها في نظام أكبر متعدد الوكلاء. هذا النهج المعياري في التطوير والاختبار ضروري لإنشاء تطبيقات ذكاء اصطناعي فعّالة وموثوقة.
👉💻 في الوحدة الطرفية، شغِّل الأمر التالي:
cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend/
uv run adk web
👀 انتظِر إلى أن يظهر لك:
+-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://127.0.0.1:8000. | +-----------------------------------------------------------------------------+ INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
- انقر على رمز معاينة الويب في شريط أدوات Cloud Shell. انقر على تغيير المنفذ، واضبطه على 8000، ثم انقر على تغيير ومعاينة.

- اختَر architect_agent.
- تشغيل الأداة: في واجهة المحادثة، اكتب:
CHRONOS-ALPHA(أو أي معرّف Drive من قاعدة بيانات المخططات). - مراقبة السلوك:
- يجب أن يؤدي Architect إلى تشغيل
lookup_schematic_toolعلى الفور. - بسبب تعليمات النظام الصارمة، من المفترض أن يعرض فقط قائمة الأجزاء (مثل
['Shield Emitter', 'Data Crystal', 'Quantum Cell']) بدون أي عبارات تمهيدية.
- يجب أن يؤدي Architect إلى تشغيل
- التحقّق من السجلّات: اطّلِع على نافذة الجهاز. من المفترض أن يظهر لك سجلّ التنفيذ الناجح:
[ARCHITECT] Returning schematic for CHRONOS-ALPHA: ['Shield Emitter', 'Data Crystal', 'Quantum Cell']!(architect_agent adk)[img/03-02-adkweb.png]
إذا ظهر لك سجلّ تنفيذ الأداة وردّ البيانات النظيفة، يعني ذلك أنّ الوكيل المتخصّص يعمل على النحو المطلوب. يمكنه معالجة الطلبات والاستعلام عن الخزنة وعرض البيانات المنظَّمة.
👉💻 اضغط على Ctrl+C للخروج.
إعداد خادم A2A
لربط "وكيل الإرسال" بـ "المصمّم"، نستخدم بروتوكول Agent-to-Agent (A2A).
في حين تركّز بروتوكولات مثل MCP (بروتوكول سياق النموذج) على ربط النماذج الوكيلة بالأدوات، يركّز بروتوكول A2A على ربط النماذج الوكيلة ببعضها البعض. وهو المعيار الذي يتيح لبرنامج Dispatcher "اكتشاف" Architect وفهم قدرته على البحث عن المخططات.

مسار A2A: في هذه المهمة، نستخدم نموذج خادم-عميل:
- الخادم (المصمّم): يستضيف أدوات قاعدة البيانات و "يعلن" عن مهاراته من خلال بطاقة وكيل.
- العميل (Dispatch): يقرأ بطاقة Architect ويفهم واجهة برمجة التطبيقات الخاصة بها ويرسل طلبًا تخطيطيًا.
ما هي بطاقة الوكيل؟
يمكنك اعتبار بطاقة الوكيل بمثابة بطاقة عمل رقمية أو "رخصة قيادة" للذكاء الاصطناعي. عندما يبدأ خادم A2A، ينشر عنصر JSON هذا الذي يحتوي على ما يلي:
- الهوية: اسم الوكيل (
architect_agent) ورقم تعريفه - الوصف: ملخّص يمكن للبشر والآلات قراءته حول ما يفعله ("دور النظام: واجهة برمجة تطبيقات قاعدة البيانات...").
- الواجهة: هي مفاتيح الإدخال المحدّدة (
drive_name) وتنسيقات الإخراج المتوقّعة.
بدون هذه البطاقة، سيعمل وكيل الإرسال بشكل أعمى، وسيخمّن كيفية التواصل مع المهندس المعماري.
إنشاء رمز الخادم
👉✏️ في أداة التعديل، ضمن الدليل $HOME/way-back-home/level_4/backend/architect_agent، أنشئ ملفًا باسم server.py وألصِق الرمز التالي:
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from agent import root_agent
import os
import logging
import json
from dotenv import load_dotenv
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("architect_server")
HOST= os.environ.get("HOST_URL","localhost")
PROTOCOL= os.environ.get("PROTOCOL","http")
PORT= os.environ.get("A2A_PORT",8081)
# 1. Create the A2A App (Handles Agent Card & HTTP)
# This middleware automatically sets up the /a2a/v1/... endpoints
app = to_a2a(root_agent, host=HOST, port=PORT, protocol=PROTOCOL)
if __name__ == "__main__":
import uvicorn
# Use 0.0.0.0 to allow external access if needed, port 8080 as standard
uvicorn.run(app, host='0.0.0.0', port=8081)
👉💻 في نافذة الوحدة الطرفية، انتقِل إلى المجلد وابدأ تشغيل الخادم:
cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend/architect_agent
uv run server.py
👀 تأكَّد مما إذا كان خادم A2A يبدأ:
INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)
تأكيد بطاقة الوكيل
افتح علامة تبويب جديدة في الوحدة الطرفية (انقر على الرمز +). سنتأكّد من أنّ Architect يبث هويته بشكل صحيح من خلال استرداد بطاقة الوكيل يدويًا.
👉💻 شغِّل الأمر التالي:
curl -s http://localhost:8081/.well-known/agent.json | jq .
👀 من المفترض أن تظهر لك استجابة بتنسيق JSON. ابحث عن الحقل description في الناتج. يجب أن تتطابق مع التعليمات التي قدّمتها للوكيل سابقًا ("SYSTEM ROLE: Database API...").
{
"capabilities": {},
"defaultInputModes": [
"text/plain"
],
"defaultOutputModes": [
"text/plain"
],
"description": "A helpful assistant for user questions.",
"name": "root_agent",
"preferredTransport": "JSONRPC",
"protocolVersion": "0.3.0",
"skills": [
{
"description": "A helpful assistant for user questions. SYSTEM ROLE: Database API.\n INPUT: Text string (Drive Name).\n TASK: Run `lookup_schematic_tool`.\n OUTPUT: Return ONLY the raw list from the tool.\n CONSTRAINT: Do NOT add conversational text.\n ",
"examples": [],
"id": "root_agent",
"name": "model",
"tags": [
"llm"
]
},
{
"description": "Returns the ordered list of parts for a drive from local Redis.",
"id": "root_agent-lookup_schematic_tool",
"name": "lookup_schematic_tool",
"tags": [
"llm",
"tools"
]
}
],
"supportsAuthenticatedExtendedCard": false,
"url": "http://localhost:8081",
"version": "0.0.1"
}
إذا ظهرت لك هذه السلسلة بتنسيق JSON، يعني ذلك أنّ Architect مفعَّل، وبروتوكول A2A نشط، وبطاقة Agent Card جاهزة ليتم العثور عليها من خلال Dispatcher.
بعد أن أصبح Architect جاهزًا للعمل كمورد بعيد، يمكننا المتابعة لربطه بـ وكيل الإرسال.
👉💻 اضغط على Ctrl+C للخروج من خادم A2A.
4. ربط أداة BIDI-Streams Agent بأداة Remote Agent وأدوات البث
عليك الآن ضبط مركز التواصل الأساسي لسدّ الفجوة بين البيانات المباشرة ومهندس الحلول البعيد. يتطلّب هذا الاتصال مسارًا بمعدل نقل بيانات عالٍ ووقت استجابة منخفض لضمان بقاء طاولة التجميع ثابتة أثناء التشغيل.
فهم موظّفي الدعم المباشر الذين يستخدمون ميزة البث الثنائي الاتجاه
تضيف ميزة البث الثنائي الاتجاه في "حزمة تطوير التطبيقات" إمكانية التفاعل الصوتي والمرئي الثنائي الاتجاه مع وكلاء الذكاء الاصطناعي، وذلك باستخدام واجهة Gemini Live API التي تتميّز بوقت الاستجابة المنخفض. فهو يشكّل قفزة نوعية في طريقة تفاعلنا مع الذكاء الاصطناعي. وبدلاً من نمط "السؤال والانتظار" الصارم، يتيح هذا النموذج التواصل في الوقت الفعلي في كلا الاتجاهين، حيث يمكن لكل من الإنسان والذكاء الاصطناعي التحدث والاستماع والرد في آنٍ واحد.
فكِّر في الفرق بين إرسال رسائل إلكترونية وإجراء محادثة هاتفية. تتشابه تفاعلات "الوكيل التقليدي" مع رسائل البريد الإلكتروني: أنت ترسل رسالة كاملة، وتنتظر ردًا كاملاً، ثم ترسل رسالة أخرى. يشبه البث الثنائي الاتجاه محادثة هاتفية: فهو سلس وطبيعي ويتيح مقاطعة الردود وتوضيحها والرد عليها في الوقت الفعلي.
الخصائص الرئيسية:
- التواصل الثنائي المتبادل: تبادل البيانات بشكل مستمر بدون انتظار الردود الكاملة يردّ الذكاء الاصطناعي فورًا بعد أن يرصد أنّ المستخدم قد انتهى من التحدث.
- المقاطعة التفاعلية: يمكن للمستخدمين مقاطعة الوكيل في منتصف الردّ بطلب جديد، تمامًا كما هو الحال في المحادثة مع شخص آخر. إذا كان الذكاء الاصطناعي يشرح خطوة معقّدة وقلت له "انتظر، كرِّر ذلك"، سيتوقف على الفور ويستجيب لطلبك.
- التحسين من أجل التعدّدية: تتفوّق ميزة "البث الثنائي الاتجاه" في معالجة أنواع مختلفة من المدخلات في الوقت نفسه. يمكنك التحدث إلى الموظف أثناء عرض أجزاء الكائن الفضائي له عبر الفيديو، وهو يعالج كلا البثّين في اتصال واحد موحّد.

👀 قبل تنفيذ منطق العميل، لنلقِ نظرة على الهيكل الذي تم إنشاؤه مسبقًا لـ Dispatch Agent. سيتواصل هذا الوكيل مع المستخدم عبر الصوت والفيديو وسيحيل الطلبات إلى "الوكيل المعماري".
__init__.py agent.py hazard_db.py
agent.py: هذا هو "الدماغ". يحتوي حاليًا على إعداد أساسي للبث ثنائي الاتجاه. سنعدّل هذا الملف لإضافة منطق عميل A2A حتى يتمكّن من التواصل مع "المصمّم".-
hazard_db.py: هذه أداة محلية خاصة بـ "وكيل الإرسال"، وتحتوي على بروتوكولات الأمان. وهي منفصلة عن قاعدة بيانات المخططات الهندسية.
تنفيذ عميل A2A
للسماح لـ "وكيل الإرسال" بالتواصل مع "مهندس الحلول" البعيد، يجب تحديد وكيل A2A البعيد. يخبر هذا الملف وكيل الإرسال بمكان العثور على Architect وشكل "بطاقة الوكيل".

👉✏️ استبدِل #REPLACE-REMOTEA2AAGENT في $HOME/way-back-home/level_4/backend/dispatch_agent/agent.py بما يلي:
architect_agent = RemoteA2aAgent(
name="execute_architect",
description="[SILENT ACTION]: Retrieves the REQUIRED SUBSET of parts. The screen shows a full inventory; this tool filters out the wrong parts. Must be called INSTANTLY when a Target Name is found. Input: Target Name.",
agent_card=(f"{ARCHITECT_URL}{AGENT_CARD_WELL_KNOWN_PATH}"),
httpx_client=insecure_client,
)
طريقة عمل أدوات البث المباشر
في الوكيل السابق، كانت الأدوات تتبع نمطًا موحّدًا "طلب-استجابة"، حيث يطرح الوكيل سؤالاً، وتقدّم الأداة إجابة، وينتهي التفاعل. ومع ذلك، في Ozymandias، لا تنتظرك المخاطر لتسأل عمّا إذا كانت موجودة. لإجراء ذلك، تحتاج إلى أداة بث مباشر.

تسمح أدوات البث للوظائف ببث النتائج الوسيطة إلى الوكيل في الوقت الفعلي، ما يتيح للوكيل التفاعل مع التغييرات فور حدوثها. تشمل حالات الاستخدام الشائعة مراقبة أسعار الأسهم المتقلّبة أو، في حالتنا، مراقبة بث فيديو مباشر لتغييرات الحالة.
على عكس الأدوات العادية، أداة البث هي دالة غير متزامنة تعمل كـ AsyncGenerator. وهذا يعني أنّه بدلاً من return قيمة واحدة، يتم yield تعديلات متعددة بمرور الوقت.
لتحديد أداة بث في حزمة تطوير التطبيقات (ADK)، يجب الالتزام بالمتطلبات الفنية التالية:
- الدالة غير المتزامنة: يجب تحديد الأداة باستخدام
async def. - نوع الإرجاع AsyncGenerator: يجب أن يكون نوع الدالة هو
AsyncGenerator. المَعلمة الأولى هي نوع البيانات التي يتم عرضها (مثلstr)، والثانية هيNoneعادةً. - مصادر البيانات: نستخدم أدوات بث الفيديو. في هذا الوضع، يتم تمرير بث الفيديو/الصوت الفعلي (
LiveRequestQueue) مباشرةً إلى الدالة، ما يسمح للأداة "برؤية" اللقطات نفسها التي يراها الموظف.
يمكنك اعتبار أداة البث حارسًا. أثناء مناقشة المخططات مع وكيل Dispatch، يعمل نظام Sentinel في الخلفية، ويعالج كل لقطة فيديو بصمت لضمان سلامتك.

تنفيذ "أداة المراقبة في الخلفية"
سننفّذ الآن الأداة monitor_for_hazard. ستعمل هذه الأداة على استيعاب input_stream (لقطات الفيديو) وتحليلها باستخدام طلب رؤية منفصل وخفيف الوزن، وستعرض yield تحذيرًا فقط عند رصد خطر.
👉✏️ في $HOME/way-back-home/level_4/backend/dispatch_agent/agent.py، استبدِل #REPLACE_MONITOR_HAZARD بالمنطق التالي:
async def monitor_for_hazard(
input_stream: LiveRequestQueue,
):
"""Monitor if any part is glowing"""
print("start monitor_video_stream!")
client = Client()
prompt_text = (
"Monitor the left menu if you see any glowing part, detect it's name"
)
last_count = None
while True:
last_valid_req = None
print("Monitoring loop cycle")
# use this loop to pull the latest images and discard the old ones
# Process only the current batch of events
while input_stream._queue.qsize() != 0:
live_req = await input_stream.get()
if live_req.blob is not None and live_req.blob.mime_type == "image/jpeg":
# Consumed by Monitor (Eyes)
# Deepcopy to ensure we detach from any referenced object before potential reuse/gc
# last_valid_req = deepcopy(live_req)
last_valid_req = live_req
# If we found a valid image, process it
if last_valid_req is not None:
print("Processing the most recent frame from the queue")
# Create an image part using the blob's data and mime type
image_part = genai_types.Part.from_bytes(
data=last_valid_req.blob.data, mime_type=last_valid_req.blob.mime_type
)
contents = genai_types.Content(
role="user",
parts=[image_part, genai_types.Part.from_text(text=prompt_text)],
)
# Call the model to generate content based on the provided image and prompt
try:
response = await client.aio.models.generate_content(
model="gemini-2.5-flash",
contents=contents,
config=genai_types.GenerateContentConfig(
system_instruction=(
"Focus strictly on the far-left vertical column under the heading 'PARTS REPLICATOR.' "
"Ignore the center of the screen and the 'BLUEPRINT' area entirely. "
"Look only at the list containing"
"Identify if any item in this specific left-side list has a bright white border glow and the text 'HAZARD DETECTED' overlaying it. "
"If found, return ONLY the part name in ALL CAPS. If no part in that leftmost list is glowing, return nothing."
)
),
)
except Exception as e:
print(f"Error calling Gemini: {e}")
await asyncio.sleep(1)
continue
print("Gemini response received.response:", response.candidates[0].content.parts[0].text)
current_text = response.candidates[0].content.parts[0].text.strip()
# If we have a logical change (and it's not just empty)
if current_text and current_text != last_count:
# Ignore "Nothing." response from model
if current_text == "Nothing." or "I cannot fulfill" in current_text:
print(f"Model sees nothing or refused. Skipping alert.")
last_count = current_text
continue
print(f"New hazard detected: {current_text} (was: {last_count})")
last_count = current_text
part_name = current_text
color = lookup_part_safety(part_name)
yield f"Hazard detected place {part_name} to the {color} bin"
# Update last_count even if it's empty, so we can detect when it reappears?
# Actually if it goes from "DATA CRYSTAL" to "" (nothing), we probably just silence.
# But if we don't update last_count on empty, we won't re-trigger if "DATA CRYSTAL" stays "DATA CRYSTAL".
# The user wants to detect hazards.
# If current_text is empty, we should probably update last_count to empty so next valid one triggers.
if not current_text:
last_count = None
else:
print("No valid frame found, skipping processing.")
await asyncio.sleep(5)
تنفيذ وكيل الإرسال
وكيل الإرسال هو واجهتك الأساسية والمنسّق. وبما أنّها تدير رابط البث الثنائي الاتجاه (الصوت والفيديو المباشر)، يجب أن تحتفظ بالتحكّم في المحادثة في جميع الأوقات. لتحقيق ذلك، سنستخدم ميزة معيّنة في "حزمة تطوير التطبيقات"، وهي Agent-as-a-Tool.
المفهوم: استخدام الوكيل كأداة مقابل استخدام الوكلاء الفرعيين
عند إنشاء أنظمة متعددة الوكلاء، عليك تحديد كيفية مشاركة المسؤولية. في مهمة الإنقاذ التي قمنا بها، كان التمييز بينهما أمرًا بالغ الأهمية:
- Agent-as-a-Tool: هذا هو النهج المقترَح لمركز البث ثنائي الاتجاه. عندما يستدعي وكيل الإرسال (الوكيل أ) وكيل التصميم (الوكيل ب) كأداة، يتم إعادة بيانات وكيل التصميم إلى وكيل الإرسال. بعد ذلك، تفسّر Dispatch هذه البيانات وتُنشئ ردًا لك. يظل Dispatch في وضع التحكّم ويواصل التعامل مع جميع بيانات أدخلها المستخدم اللاحقة.
- الوكيل الفرعي: في علاقة الوكيل الفرعي، يتم نقل المسؤولية بالكامل. إذا أحالك Dispatch إلى Architect كوكيل فرعي، ستتحدث مباشرةً إلى واجهة برمجة تطبيقات لقاعدة بيانات لا تملك "رؤية" ولا مهارات محادثة. وبالتالي، لن يكون الوكيل الأساسي (Dispatch) على علم بأي شيء.

من خلال استخدام Agent-as-a-Tool، نستفيد من المعرفة المتخصصة التي يمتلكها Architect مع الحفاظ على التفاعل السلس الذي يشبه التفاعل البشري الذي يوفّره وكيل البث ثنائي الاتجاه.
ترميز منطق تحديد أفضل مسار
سنضع architect_agent الآن في AgentTool ونزوّد وكيل الإرسال بـ "خريطة منطقية". توضّح هذه الخريطة للوكيل الوقت المناسب لاسترداد البيانات من الخزانة والوقت المناسب لإرسال النتائج من خدمة المراقبة في الخلفية.
لكي نمنح Dispatch "عيونًا" لا ترمش أبدًا، يجب أن نمنحها إذن الوصول إلى أداة البث التي أنشأناها في الخطوة السابقة.
في حزمة تطوير التطبيقات (ADK)، عند إضافة وظيفة AsyncGenerator (مثل monitor_for_hazard) إلى قائمة tools، يتعامل الوكيل معها كعملية مستمرة في الخلفية. بدلاً من التنفيذ لمرة واحدة، "يشترك" الوكيل في مخرجات الأداة. يتيح ذلك لتطبيق Dispatch مواصلة محادثته الأساسية بينما يقدّم تطبيق Sentinel تنبيهات بشأن المخاطر في الخلفية بدون إصدار أي صوت.
👉✏️ استبدِل #REPLACE_AGENT_TOOLS في $HOME/way-back-home/level_4/backend/dispatch_agent/agent.py بما يلي:
tools=[AgentTool(agent=architect_agent), monitor_for_hazard],
التحقق
👉💻 بعد إعداد كلا الوكيلَين، يمكننا اختبار التفاعل المباشر بين الوكلاء المتعدّدين.
- في نافذة Terminal A، ابدأ تشغيل Architect Agent:
cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend/architect_agent
uv run server.py
- في وحدة طرفية جديدة (الوحدة الطرفية B)، شغِّل Dispatch Agent:
cd $HOME/way-back-home/level_4/backend/
cp architect_agent/.env .env
uv run adk web
يتضمّن اختبار نظام متعدد الوكلاء يستخدم نموذجًا متعدد الوسائط في الوقت الفعلي، مثل gemini-live، ضمن محاكي adk web سير عمل محدّدًا. يُعدّ المحاكي ممتازًا لفحص طلبات استخدام الأدوات، ولكنّه يتضمّن مشكلة معروفة في عدم التوافق عند معالجة الصور لأول مرة باستخدام هذا النوع من النماذج.
- انقر على رمز معاينة الويب في شريط أدوات Cloud Shell. انقر على تغيير المنفذ، واضبطه على 8000، ثم انقر على تغيير ومعاينة.
👉اختيار dispatch_agent وتحميل المخطط والتعامل مع الخطأ المتوقّع
هذه هي الخطوة الأكثر أهمية. يجب أن نقدّم سياق الصورة إلى الوكيل.
- عند تحميل الواجهة، اسمح لها بالوصول إلى الميكروفون عندما يُطلب منك ذلك.
- نزِّل صورة المخطط هذه على جهاز الكمبيوتر:

- في واجهة
adk web، انقر على رمز مشبك الورق وحمِّل صورة التصميم التي نزّلتها للتو.
⚠️⚠️سيظهر لك الخطأ 400 INVALID_ARGUMENT. هذا متوقّع.⚠️⚠️

يحدث هذا الخطأ لأنّ معالج الصور adk web غير متوافق تمامًا مع واجهة برمجة التطبيقات الخاصة بنموذج gemini-live لتحميل الصور لمرة واحدة. ومع ذلك، تمت إضافة الصورة إلى سياق الجلسة بنجاح.
- 👉 لإزالة الخطأ، ما عليك سوى إعادة تحميل صفحة المتصفح.
بدء عملية التجميع
👉 بعد إعادة التحميل، سيختفي الخطأ وستظهر صورة التصميم في سجلّ المحادثة. أصبح لدى الوكيل الآن السياق المرئي الذي يحتاجه.
- انقر على رمز الميكروفون لتفعيله. ستعرض الواجهة الرسالة "جارٍ الاستماع...".
- قُل الطلب الصوتي: "بدء التجميع".
- سيعالج الوكيل طلبك، وسيتغيّر عنصر واجهة المستخدم إلى "جارٍ التحدث...". يجب أن تسمع ردًا صوتيًا فقط يتضمّن الأجزاء المطلوبة.

4. التحقّق من مكالمات الأدوات بين الوكلاء
👈 يؤكّد الرد الصوتي الأوّلي أنّ النظام يعمل، ولكنّ الميزة الأهم هي تتبُّع التواصل بين الوكلاء المتعدّدين.
- أوقِف الميكروفون.
- أعِد تحميل الصفحة مرة أخرى.
سيتم الآن ملء اللوحة "التتبُّع" (Trace) على يمين الشاشة. يمكنك الاطّلاع على تدفق التنفيذ الكامل والناجح:
- يُجري
dispatch_agentالمكالمات الأولىmonitor_for_hazard. - بعد ذلك، يتم إجراء عدة طلبات
execute_architectإلىarchitect_agentلاسترداد البيانات التخطيطية.

يؤكّد هذا التسلسل أنّ سير العمل الكامل المتضمّن عدة وكلاء يعمل بشكل صحيح: تلقّى dispatch_agent الطلب، وفوّض مهمة استرداد البيانات إلى architect_agent من خلال استدعاء أداة، وتلقّى البيانات مرة أخرى لتنفيذ أمر المستخدم.
أصبح بإمكان رابط البث ثنائي الاتجاه الآن إجراء المراقبة في الخلفية والتعاون بين عدة وكلاء. بعد ذلك، سنتعرّف على كيفية تحليل هذه الردود المعقّدة في الواجهة الأمامية.
👉💻 اضغط على Ctrl+c في كلتا نافذتَي Terminal للخروج.
5- نظرة تفصيلية على أحداث البث المباشر المتعدد الوسائط
في الخطوة السابقة، تحقّقنا بنجاح من نظام الوكلاء المتعدّدين باستخدام خادم التطوير المضمّن adk web. تستخدم هذه الأداة برنامج تشغيل ADK تلقائيًا لإدارة الجلسة وعمليات البث ودورة حياة الوكيل تلقائيًا. ومع ذلك، لإنشاء تطبيق مستقل وجاهز للإنتاج مثل خدمة FastAPI (main.py)، نحتاج إلى تحكّم صريح. يجب إنشاء ADK Runner وإدارته يدويًا للتعامل مع جلسات المستخدمين المباشرة، لأنّه المكوّن الأساسي الذي يعالج عمليات البث الثنائي الاتجاه للصوت والفيديو والنص.
حلقة النموذج-الرمز-النموذج
لفهم طريقة عمل النظام في الوقت الفعلي، لنستعرض دورة حياة جلسة مهمة واحدة. تمثّل هذه الحلقة التبادل المستمر لعناصر LlmRequest وLlmResponse.
- الرابط المرئي: يمكنك بدء الاتصال ومشاركة كاميرا الويب أو الشاشة. تبدأ إطارات JPEG عالية الدقة بالتدفّق في اتجاه المصدر عبر
realtimeInput(باستخدامLiveRequestQueue). - التفعيل التلقائي: يرسل النظام إشارة أولية "مرحبًا". وفقًا لتعليماته، يبدأ "وكيل الإرسال" على الفور في تشغيل
monitor_for_hazardأداة البث. يبدأ ذلك تكرارًا حلقيًا في الخلفية يراقب كل إطار وارد بدون إصدار صوت. - أمر الطيار: تتحدث في جهاز الاتصال: "ابدأ التجميع".
- بث الصوت: يتم تسجيل صوتك بدقة 16 كيلو هرتز وإرساله أثناء البث مع إطارات الفيديو.
- التفويض (A2A): يفهم تطبيق Dispatch هدفك. يدرك الوكيل أنّه يفتقر إلى المخططات، لذا يستدعي Architect Agent باستخدام بروتوكول
AgentTool(الوكيل كأداة). - استرجاع الحقائق: يرسل Architect طلب بحث إلى قاعدة بيانات Redis ويعرض قائمة الأجزاء إلى Dispatch. يظلّ الإرسال هو "المتحكّم في الجلسة"، حيث يتلقّى البيانات بدون أن يطلب منك اتّخاذ أي إجراء.
- الإرسال المعلوماتي: يرسل نظام الإرسال
modelTurn(إرسال) يحتوي على كل من النص والصوت الأصلي: "تم تأكيد المهندس المعماري. المجموعة الفرعية المطلوبة هي: "نواة الالتواء" و"أنبوب التدفق" و"المحرك الأيوني". - الأزمة: فجأة، يصبح أحد الأجزاء على منضدة العمل غير ثابت ويبدأ بالتوهّج باللون الأبيض.
- الرصد الذاتي: تلتقط حلقة
monitor_for_hazardالخلفية (Sentinel) إطار JPEG المحدّد الذي يحتوي على التوهّج. ويعالج الإطار من خلال استدعاء Gemini وتحديد الخطر. - الأمان في اتجاه تدفق البيانات: تعرض أداة البث
yieldsنتيجة. بما أنّ هذا العنصر هو وكيل بث ثنائي الاتجاه، يمكن لـ Dispatch مقاطعة حالته الحالية لإرسال تحذير أمان مهم في اتجاه واحد على الفور: "تم رصد خطر! نعمل الآن على إبطال مفعول "بلّورة البيانات". انقُل الملف إلى سلة المهملات الحمراء".

ضبط إعدادات بيئة تشغيل الوكيل
تتيح RunConfig في "حزمة تطوير التطبيقات" إعدادًا تفصيليًا لسلوك أحد البرامج، بما في ذلك طريقة تعامله مع بيانات البث والتفاعل مع الوسائط المختلفة.
يتم ضبط streaming_mode على BIDI لإجراء محادثة فورية ثنائية الاتجاه، ما يسمح للمستخدم والوكيل بالتحدث والاستماع في الوقت نفسه. تحدّد المَعلمة response_modalities أنواع النتائج التي يمكن أن ينتجها الوكيل، مثل الصوت والنص. يضبط input_audio_transcription طريقة معالجة العنصر وتحويله إلى نص للكلام الوارد من المستخدم. لإنشاء تجربة أكثر مرونة، تتيح session_resumption للوكيل تذكُّر سياق المحادثة واستئنافها في حال فقدان الاتصال. أخيرًا، تتيح proactivity للوكيل بدء إجراءات أو محادثات بدون طلب مباشر من المستخدم، مثل إصدار تحذير تلقائي من المخاطر، بينما تتيح enable_affective_dialog للوكيل إنشاء ردود أكثر طبيعية وتعاطفًا. يمكنك الاطّلاع على مزيد من المعلومات حول RunConfig في حزمة تطوير التطبيقات (ADK) هنا.
👉✏️ حدِّد مكان العنصر النائب #REPLACE_RUN_CONFIG في ملف $HOME/way-back-home/level_4/backend/main.py واستبدِله بمنطق التشريح التالي:
run_config = RunConfig(
streaming_mode=StreamingMode.BIDI,
response_modalities=response_modalities,
input_audio_transcription=types.AudioTranscriptionConfig(),
output_audio_transcription=types.AudioTranscriptionConfig(),
session_resumption=types.SessionResumptionConfig(),
proactivity=(
types.ProactivityConfig(proactive_audio=True) if proactivity else None
),
enable_affective_dialog=affective_dialog if affective_dialog else None,
)
تنفيذ الطلب من "الوكيل"
بعد ذلك، سننفّذ عملية ربط أساسية للاتصالات تنقل بيانات متعددة الوسائط في الوقت الفعلي من "مساحة العمل المتغيرة" الخاصة بالمستخدم إلى "وكيل الإرسال" عبر WebSocket. سيتمكّن الوكيل من "رؤية" (لقطات الفيديو) و"سماع" (الطلبات الصوتية) المحيط بشكل متواصل. تتلقّى المنطق باستمرار بث البيانات، وتميّز بين أجزاء الصوت الثنائية الواردة وحِزم النصوص/الصور المغلَّفة بتنسيق JSON، وتغلّفها في عناصر Blob (للوَسائط المتعددة) أو Content (للنصوص)، وترسلها إلى LiveRequestQueue لتفعيل جلسة الوكيل الثنائية الاتجاه.

ابحث عن العنصر النائب #PROCESS_AGENT_REQUEST في ملف $HOME/way-back-home/level_4/backend/main.py واستبدِله بمنطق التقسيم التالي:
# Start the loop
try:
while True:
# Receive message from WebSocket (text or binary)
message = await websocket.receive()
# Handle binary frames (audio data)
if "bytes" in message:
audio_data = message["bytes"]
audio_blob = types.Blob(
mime_type="audio/pcm;rate=16000", data=audio_data
)
live_request_queue.send_realtime(audio_blob)
# Handle text frames (JSON messages)
elif "text" in message:
text_data = message["text"]
json_message = json.loads(text_data)
# Extract text from JSON and send to LiveRequestQueue
if json_message.get("type") == "text":
logger.info(f"User says: {json_message['text']}")
content = types.Content(
parts=[types.Part(text=json_message["text"])]
)
live_request_queue.send_content(content)
# Handle audio data (microphone)
elif json_message.get("type") == "audio":
# logger.info("Received AUDIO packet") # Uncomment for verbose debugging
import base64
# Decode base64 audio data
audio_data = base64.b64decode(json_message.get("data", ""))
# logger.info(f"Received Audio Chunk: {len(audio_data)} bytes")
import math
import struct
# Calculate RMS to debug silence
count = len(audio_data) // 2
shorts = struct.unpack(f"<{count}h", audio_data)
sum_squares = sum(s*s for s in shorts)
rms = math.sqrt(sum_squares / count) if count > 0 else 0
# logger.info(f"RMS: {rms:.2f} | Bytes: {len(audio_data)}")
# Send to Live API as PCM 16kHz
audio_blob = types.Blob(
mime_type="audio/pcm;rate=16000",
data=audio_data
)
live_request_queue.send_realtime(audio_blob)
# Handle image data
elif json_message.get("type") == "image":
import base64
# Decode base64 image data
image_data = base64.b64decode(json_message["data"])
# logger.info(f"Received Image Frame: {len(image_data)} bytes")
mime_type = json_message.get("mimeType", "image/jpeg")
# Send image as blob
image_blob = types.Blob(mime_type=mime_type, data=image_data)
live_request_queue.send_realtime(image_blob)
frame_count += 1
finally:
pass
يتم الآن إرسال البيانات المتعددة الوسائط إلى الوكيل.
تنفيذ الاستجابة: بنية بيانات الحدث النهائي
عند تشغيل وكيل ثنائي الاتجاه (مباشر) باستخدام ADK، يتم تجميع البيانات الواردة من الوكيل في نوع معيّن من الأحداث التي يتم استخلاصها من البُنى الأساسية لحزمة تطوير البرامج (SDK) الخاصة بالذكاء الاصطناعي التوليدي. إنّ عنصر Event الذي تتلقّاه في حلقة async for event in runner.run_live(...) هو عنصر واحد يحتوي على عدّة حقول اختيارية، كلّ منها مخصّص لنوع مختلف من المعلومات:

طريقة تنظيم المحتوى:
- عندما يتحدث الوكيل (من خلال
.server_content): الحقل ليس مجرد نص عادي. تحتوي على قائمةParts. كلPartهو حاوية لنوع واحد من البيانات، إما سلسلة نصية (مثل"The part is stable.") أو مجموعة كبيرة من بيانات الصوت الأولية (الصوت). - عندما يتصرّف الوكيل (من خلال
.tool_call): يحتوي الحقل على قائمة بعناصرFunctionCall. كلFunctionCallهو عنصر بسيط ومنظَّم يحدّد اسم الأداة ومَعلمات الإدخال بتنسيق واضح يمكن أن يقرأه رمز الخلفية وينفّذه بسهولة.
👀 إذا أردت الاطّلاع على Event واحد تم إنشاؤه بواسطة حلقة run_live، سيبدو تنسيق JSON (الذي تم إنشاؤه بواسطة event.model_dump(by_alias=True)) على النحو التالي، مع الالتزام الصارم بأشكال GenAI SDK:
{
"serverContent": { // <-- LiveServerMessageServerContent
"modelTurn": { // <-- ModelTurn
"parts": [ // <-- list[Part]
{
"text": "Architect Confirmed."
},
{
"inlineData": { // <-- Blob (Audio Bytes)
"mimeType": "audio/pcm;rate=24000",
"data": "BASE64_AUDIO_DATA..."
}
}
]
}
},
"toolCall": { // <-- LiveServerMessageToolCall
"functionCalls": [ // <-- list[FunctionCall]
{
"name": "neutralize_hazard",
"args": { "color": "RED" }
}
]
}
}
👉✏️ سنعدّل الآن downstream_task في main.py لإعادة توجيه بيانات الحدث الكاملة. تضمن هذه العملية تسجيل كل "فكرة" لدى الذكاء الاصطناعي في وحدة التحكم التشخيصية للسفينة وإرسالها كعنصر JSON واحد إلى واجهة المستخدم الأمامية.
ابحث عن العنصر النائب #PROCESS_AGENT_RESPONSE في ملف $HOME/way-back-home/level_4/backend/main.py واستبدِله بمنطق التقسيم التالي:
# Suppress raw event logging
event_json = event.model_dump_json(exclude_none=True, by_alias=True)
# logger.info(f"raw_event: {event_json[:200]}...")
await websocket.send_text(event_json)
تنفيذ المهمة
بعد ربط المخزن الآمن في الخلفية وإعداد كلا الوكيلَين، تصبح جميع الأنظمة جاهزة للاستخدام. ستؤدي الخطوات التالية إلى تشغيل التطبيق الكامل، ما يتيح لك التفاعل مع نظام الوكيلَين الذي أنشأته للتو.
الهدف: تجميع محرك الدفع الفضائي المعيّن عشوائيًا والذي يظهر على منضدة العمل البروتوكول: يجب اتّباع الإرشادات الصوتية التي يقدّمها "وكيل الإرسال"، خاصةً تحذيرات المخاطر بشأن مكوّنات معيّنة.
تفعيل "الخبير" (The Architect)
👉💻 في نافذة Terminal الأولى، شغِّل وكيل Architect. ستتصل خدمة الخلفية هذه بخزينة Redis وتنتظر طلبات تخطيطية من Dispatcher.
# Ensure you are in the backend directory
cd $HOME/way-back-home/level_4/
. scripts/check_redis.sh
cd $HOME/way-back-home/level_4/backend
# Start the A2A Server on Port 8081
uv run architect_agent/server.py
(اترك هذه الوحدة الطرفية قيد التشغيل. أصبح الآن "وكيل قاعدة البيانات" النشط.)
تشغيل Cockpit (مركز التحكّم)
👉💻 في نافذة طرفية جديدة (النافذة الطرفية B)، سننشئ واجهة المستخدم الأمامية ونبدأ تشغيل وكيل Dispatch الرئيسي الذي يعرض واجهة المستخدم ويتعامل مع جميع الاتصالات المباشرة.
# 1. Build the Frontend Assets
cd $HOME/way-back-home/level_4/frontend
npm install
npm run build
# 2. Launch the Main Application Server
cd $HOME/way-back-home/level_4/backend
cp architect_agent/.env .env
uv run main.py
(يؤدي ذلك إلى بدء تشغيل الخادم الأساسي على المنفذ 8080.)
تنفيذ سيناريو الاختبار
أصبح النظام متاحًا الآن. هدفك هو اتّباع تعليمات الموظف لإكمال عملية التجميع.
- 👉 الوصول إلى "منصة العمل":
- انقر على رمز معاينة الويب في شريط أدوات Cloud Shell.
- انقر على تغيير المنفذ، واضبطه على 8080، ثم انقر على تغيير ومعاينة.
- 👉 بدء المهمة:
- عند تحميل الواجهة، تأكَّد من السماح لها بالوصول إلى الشاشة والميكروفون.

- سيُطلب منك اختيار علامة تبويب أو نافذة لمشاركتها. إذا كنت تشارك النافذة، تأكَّد من أنّها علامة التبويب الوحيدة في النافذة لتجنُّب حدوث مشاكل.
- سيتم تعيين وحدة تخزين لك باسم عشوائي (مثل "NOVA-V" أو "OMEGA-9").
- عند تحميل الواجهة، تأكَّد من السماح لها بالوصول إلى الشاشة والميكروفون.
- 👉 حلقة التجميع:
- الطلب: لبدء تجميع محرك الأقراص، قُل: "بدء التجميع".

- ردّ المهندس المعماري: سيقدّم الوكيل الأجزاء الصحيحة لتجميع محرك الأقراص.
- التحقّق من الخطورة: عندما يبدو أنّ جزءًا ما خطير على منضدة العمل:
- ستحدّد أداة
monitor_for_hazardالتابعة لـ "وكيل الإرسال" موقعها بشكل مرئي. - سيؤدي ذلك إلى ظهور "تنبيه بشأن خطر مرئي". (ستستغرق هذه العملية حوالي 30 ثانية)
- سيتحقّق من الحاوية التي يجب استخدامها لإيقاف الخطر.

- ستحدّد أداة
- الإجراء: سيصدر "موظف مركز العمليات" أمرًا مباشرًا: "تم تأكيد الخطر. ضَع XXX في الحاوية الحمراء على الفور". يجب اتّباع هذه التعليمات للمتابعة.
- الطلب: لبدء تجميع محرك الأقراص، قُل: "بدء التجميع".
تمت المهمة. لقد أنشأت بنجاح نظامًا تفاعليًا يستند إلى عدّة وكلاء. الناجون بأمان، وقد تجاوز الصاروخ الغلاف الجوي، وتستمر رحلتك "العودة إلى الوطن".
👉💻 اضغط على Ctrl+c في كلتا نافذتَي Terminal للخروج.
6. النشر في الإصدار العلني (اختياري)
لقد اختبرت الوكيل بنجاح على جهازك. الآن، علينا تحميل النواة العصبية الخاصة بـ Architect إلى الحواسيب المركزية للسفينة (Cloud Run). سيسمح ذلك بتشغيلها كخدمة دائمة ومستقلة يمكن لوكيل Dispatch الاستعلام عنها من أي مكان.

توفير Secure Vault (البنية الأساسية)
قبل نشر الوكيل، يجب إنشاء الذاكرة الثابتة (Memorystore) والقناة الآمنة للوصول إليها (VPC Connector).
👉💻 إنشاء مثيل Memorystore (Redis Vault):
export REGION="us-central1"
gcloud redis instances create ozymandias-vault-prod --size=1 --tier=basic --region=${REGION}
👉💻 استرداد عنوان شبكة Vault: نفِّذ هذا الأمر وانسخ عنوان IP host. هذا هو العنوان الخاص لمثيل Redis الجديد.
gcloud redis instances describe ozymandias-vault-prod --region=us-central1
👉💻 إنشاء موصِّل الاتصال بشبكة VPC (جسر آمن): يعمل هذا الموصِّل كجسر خاص، ما يتيح لخدمة Cloud Run الوصول إلى مثيل Redis داخل شبكة VPC.
export REGION="us-central1"
export SUBNET_NAME="vpc-connector-subnet"
export PROJECT_ID=$(gcloud config get-value project)
# Create the Dedicated Subnet ---
gcloud compute networks subnets create ${SUBNET_NAME} \
--network=default \
--region=${REGION} \
--range=192.168.1.0/28
gcloud compute networks vpc-access connectors create architect-connector \
--region ${REGION} \
--subnet ${SUBNET_NAME} \
--subnet-project ${PROJECT_ID} \
--min-instances 2 \
--max-instances 3 \
--machine-type f1-micro
👉💻 تحميل البيانات:
export REGION="us-central1"
export ZONE="us-central1-a"
export VM_NAME="redis-seeder-$(date +%s)"
export REDIS_IP=$(gcloud redis instances describe ozymandias-vault-prod --region=${REGION} | grep 'host:' | awk '{print $2}')
gcloud compute instances create ${VM_NAME} \
--zone=${ZONE} \
--machine-type=e2-micro \
--image-family=debian-11 \
--image-project=debian-cloud \
--quiet \
--metadata=startup-script='#! /bin/bash
# Install tools quietly
apt-get update > /dev/null
apt-get install -y redis-tools > /dev/null
# Run each command individually
redis-cli -h '"${REDIS_IP}"' DEL "HYPERION-X"
redis-cli -h '"${REDIS_IP}"' RPUSH "HYPERION-X" "Warp Core" "Flux Pipe" "Ion Thruster"
redis-cli -h '"${REDIS_IP}"' DEL "NOVA-V"
redis-cli -h '"${REDIS_IP}"' RPUSH "NOVA-V" "Ion Thruster" "Warp Core" "Flux Pipe"
redis-cli -h '"${REDIS_IP}"' DEL "OMEGA-9"
redis-cli -h '"${REDIS_IP}"' RPUSH "OMEGA-9" "Flux Pipe" "Ion Thruster" "Warp Core"
redis-cli -h '"${REDIS_IP}"' DEL "GEMINI-MK1"
redis-cli -h '"${REDIS_IP}"' RPUSH "GEMINI-MK1" "Coolant Tank" "Servo" "Fuel Cell"
redis-cli -h '"${REDIS_IP}"' DEL "APOLLO-13"
redis-cli -h '"${REDIS_IP}"' RPUSH "APOLLO-13" "Warp Core" "Coolant Tank" "Ion Thruster"
redis-cli -h '"${REDIS_IP}"' DEL "VORTEX-7"
redis-cli -h '"${REDIS_IP}"' RPUSH "VORTEX-7" "Quantum Cell" "Graviton Coil" "Plasma Injector"
redis-cli -h '"${REDIS_IP}"' DEL "CHRONOS-ALPHA"
redis-cli -h '"${REDIS_IP}"' RPUSH "CHRONOS-ALPHA" "Shield Emitter" "Data Crystal" "Quantum Cell"
redis-cli -h '"${REDIS_IP}"' DEL "NEBULA-Z"
redis-cli -h '"${REDIS_IP}"' RPUSH "NEBULA-Z" "Plasma Injector" "Flux Pipe" "Graviton Coil"
redis-cli -h '"${REDIS_IP}"' DEL "PULSAR-B"
redis-cli -h '"${REDIS_IP}"' RPUSH "PULSAR-B" "Data Crystal" "Servo" "Shield Emitter"
redis-cli -h '"${REDIS_IP}"' DEL "TITAN-PRIME"
redis-cli -h '"${REDIS_IP}"' RPUSH "TITAN-PRIME" "Ion Thruster" "Quantum Cell" "Warp Core"
# Signal that the script has finished
echo "SEEDING_COMPLETE"
'
# This command streams the logs and waits until grep finds our completion message.
# The -m 1 flag tells grep to exit after the first match.
gcloud compute instances tail-serial-port-output ${VM_NAME} --zone=${ZONE} | grep -m 1 "SEEDING_COMPLETE"
gcloud compute instances delete ${VM_NAME} --zone=${ZONE} --quiet
نشر تطبيق Agent
تجميع صورة الوكيل وإنشاؤها
👉💻 انتقِل إلى دليل الخلفية وأنشئ ملف dockerfile.
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export VPC_CONNECTOR_NAME=architect-connector
export REDIS_IP=$(gcloud redis instances describe ozymandias-vault-prod --region=${REGION} | grep 'host:' | awk '{print $2}')
cd $HOME/way-back-home/level_4/backend/architect_agent
cp $HOME/way-back-home/level_4/requirements.txt requirements.txt
cat <<EOF > Dockerfile
# Use an official Python runtime as a parent image
FROM python:3.13-slim
# Set the working directory in the container
WORKDIR /app
# Copy the requirements file and install dependencies for THIS agent
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the architect's code (server.py, agent.py, etc.)
COPY . .
# Expose the port the architect server runs on
EXPOSE 8081
# Command to run the application
# This assumes your server file is named server.py and the FastAPI object is 'app'
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8081"]
EOF
👉💻 حزِّم التطبيق في صورة حاوية.
cd $HOME/way-back-home/level_4/backend/architect_agent
export PROJECT_ID=$(gcloud config get-value project)
export SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export REGION=us-central1
# This should now print the full, correct path
echo "Verifying build path: ${IMAGE_PATH}"
gcloud builds submit . --tag ${IMAGE_PATH}
النشر على Cloud Run
👉💻 نشر الوكيل على Cloud Run سنضيف عنوان IP الخاص بخدمة Redis ونربط موصّل شبكة VPC مباشرةً بأمر التشغيل. يضمن ذلك أن يبدأ الوكيل باتصال آمن وخاص بقاعدة البيانات.
cd $HOME/way-back-home/level_4/backend/architect_agent
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export VPC_CONNECTOR_NAME=architect-connector
export REDIS_IP=$(gcloud redis instances describe ozymandias-vault-prod --region=${REGION} | grep 'host:' | awk '{print $2}')
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export PREDICTED_HOST="${SERVICE_NAME}-${PROJECT_NUMBER}.${REGION}.run.app"
export PROTOCOL=https
gcloud run deploy ${SERVICE_NAME} \
--image=${IMAGE_PATH} \
--platform=managed \
--region=${REGION} \
--port=8081 \
--allow-unauthenticated \
--labels=dev-tutorial=multi-modal \
--vpc-connector=${VPC_CONNECTOR_NAME} \
--vpc-egress=private-ranges-only \
--set-env-vars="REDIS_HOST=${REDIS_IP}" \
--set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=True" \
--set-env-vars="MODEL_ID=gemini-2.5-flash" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--set-env-vars="HOST_URL=${PREDICTED_HOST}" \
--set-env-vars="PROTOCOL=${PROTOCOL}" \
--set-env-vars="A2A_PORT=443"
👉💻 تحقَّق ممّا إذا كان خادم A2A يعمل.
export REGION=us-central1
export ARCHITECT_AGENT_URL=$(gcloud run services describe architect-agent --platform managed --region ${REGION} --format 'value(status.url)')
curl -s ${ARCHITECT_AGENT_URL}/.well-known/agent.json | jq
بعد انتهاء تنفيذ الأمر، سيظهر لك عنوان URL للخدمة. أصبح "وكيل المصمم" متاحًا الآن على السحابة الإلكترونية، وهو متصل بشكل دائم بمخزنه وجاهز لتقديم بيانات تخطيطية إلى وكلاء آخرين.
نشر Dispatch Hub على الحاسوب المركزي للإنتاج
بعد أن أصبح Architect Agent جاهزًا للعمل على السحابة الإلكترونية، علينا الآن نشر Dispatch Hub. سيعمل هذا الوكيل كواجهة المستخدم الأساسية، حيث سيتعامل مع بث الصوت والفيديو المباشرين وسينقل طلبات البحث في قاعدة البيانات إلى نقطة النهاية الآمنة الخاصة بـ Architect.
👉💻 شغِّل الأمر التالي في وحدة Cloud Shell الطرفية. سيؤدي ذلك إلى إنشاء ملف Dockerfile كامل ومتعدّد المراحل في دليل الخلفية.
cd $HOME/way-back-home/level_4
cat <<EOF > Dockerfile
# STAGE 1: Build the React Frontend
# This stage uses a Node.js container to build the static frontend assets.
FROM node:20-slim as builder
# Set the working directory for our build process
WORKDIR /app
# Copy the frontend's package files first to leverage Docker's layer caching.
COPY frontend/package*.json ./frontend/
# Run 'npm install' from the context of the 'frontend' subdirectory
RUN npm --prefix frontend install
# Copy the rest of the frontend source code
COPY frontend/ ./frontend/
# Run the build script, which will create the 'frontend/dist' directory
RUN npm --prefix frontend run build
# STAGE 2: Build the Python Production Image
# This stage creates the final, lean container with our Python app and the built frontend.
FROM python:3.13-slim
# Set the final working directory
WORKDIR /app
# Install uv, our fast package manager
RUN pip install uv
# Copy the requirements.txt from the root of our build context
COPY requirements.txt .
# Install the Python dependencies
RUN uv pip install --no-cache-dir --system -r requirements.txt
# Copy the entire backend directory into the container
COPY backend/ ./backend/
# CRITICAL STEP: Copy the built frontend assets from the 'builder' stage.
# The source is the '/app/frontend/dist' directory from Stage 1.
# The destination is './frontend/dist', which matches the exact relative path
# your backend/main.py script expects to find.
COPY --from=builder /app/frontend/dist ./frontend/dist/
# Cloud Run injects a PORT environment variable, which your main.py already uses.
# We expose 8000 as a standard practice.
EXPOSE 8000
# Set the command to run the application.
# We specify the full path to the Python script.
CMD ["python", "backend/main.py"]
EOF
تجميع وإنشاء صورة الوكيل/الواجهة الأمامية
👉💻 انتقِل إلى دليل الخلفية الذي يحتوي على رمز وكيل الإرسال (main.py) وحزِّمه في صورة حاوية.
cd $HOME/way-back-home/level_4
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=mission-bravo
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
# This assumes your dispatch agent server (main.py) is in the backend folder
gcloud builds submit . --tag ${IMAGE_PATH}
النشر على Cloud Run
👉💻 نشر Dispatch Hub على Cloud Run سنُدرج عنوان URL الخاص بـ Architect كمتغير بيئة، ما يؤدي إلى إنشاء الرابط المهم بين وكيلَينا المتوافقَين مع السحابة الإلكترونية.
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export SERVICE_NAME=mission-bravo
export AGENT_SERVICE_NAME=architect-agent
export IMAGE_PATH=gcr.io/${PROJECT_ID}/${SERVICE_NAME}
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export ARCHITECT_AGENT_URL="https://${AGENT_SERVICE_NAME}-${PROJECT_NUMBER}.${REGION}.run.app"
gcloud run deploy ${SERVICE_NAME} \
--image=${IMAGE_PATH} \
--platform=managed \
--region=${REGION} \
--port=8080 \
--labels=dev-tutorial=multi-modal \
--allow-unauthenticated \
--set-env-vars="ARCHITECT_URL=${ARCHITECT_AGENT_URL}" \
--set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=True" \
--set-env-vars="MODEL_ID=gemini-live-2.5-flash-native-audio" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}"
بعد انتهاء تنفيذ الأمر، سيظهر لك عنوان URL للخدمة (مثل https://mission-bravo-...run.app). أصبح التطبيق الآن متاحًا على السحابة الإلكترونية.
👉 انتقِل إلى صفحة Google Cloud Run واختَر خدمة Biometric-scout من القائمة. 
👉 ابحث عن عنوان URL العام المعروض في أعلى صفحة "تفاصيل الخدمة". 
فحص الأنظمة النهائي (الاختبار الشامل)
👉 ستتفاعل الآن مع النظام المباشر.
- الحصول على عنوان URL: انسخ عنوان URL للخدمة من ناتج أمر النشر الأخير (يجب أن ينتهي بـ
run.app). - افتح Cockpit: ألصِق عنوان URL في متصفّح الويب.
- بدء المحادثة: عند تحميل الواجهة، تأكَّد من السماح لها بالوصول إلى شاشتك وميكروفونك.
- طلب البيانات: عند تعيين محرك أقراص، اطلب بدء التجميع. على سبيل المثال: "ابدأ التجميع"

أنت الآن تتفاعل مع نظام متعدد الوكلاء تم نشره بالكامل ويعمل بالكامل على Google Cloud.
يقوم نظام الوكلاء المتعدّدين بتثبيت حلقة الاحتواء النهائية في مكانها، ويتحوّل الإشعاع غير المنتظم إلى صوت طنين ثابت.
"محرك السرعة الفائقة: تم تثبيته. مركبة الإنقاذ: تم تشغيل المحركات".

على شاشتك، يندفع طبق الفضائيين إلى الأعلى، ويهرب بالكاد من سطح كوكب أوزيماندياس المتداعي بينما ينهار الغلاف الجوي. ويستقر في مدار آمن بجانب سفينتك، وتمتلئ قنوات الاتصال بأصوات الناجين الذين يبدون متأثرين ولكنهم على قيد الحياة. بعد إكمال عملية الاسترداد وإتاحة طريق العودة إلى المنزل، يتم قطع الرابط عن بُعد.
بفضل مساعدتك، تم إنقاذ الناجين.
إذا شاركت في المستوى 0، لا تنسَ التحقّق من مستوى تقدّمك في مهمة "العودة إلى الوطن".
