‫Agentverse - The Summoner's Concord - Architecting Multi-Agent Systems

1. Overture

لقد انتهى عصر التطوير المعزول. لا يتعلّق الجيل التالي من التطور التكنولوجي بالعبقرية الفردية، بل بالمهارة التعاونية. إنّ إنشاء وكيل واحد ذكي هو تجربة رائعة. إنّ إنشاء منظومة متكاملة قوية وآمنة وذكية من البرامج الآلية، أي Agentverse حقيقي، هو التحدي الأكبر الذي يواجه المؤسسات الحديثة.

يتطلّب النجاح في هذا العصر الجديد التقاء أربعة أدوار مهمة، وهي الركائز الأساسية التي تدعم أي نظام قائم على الذكاء الاصطناعي. ويؤدي نقص في أي مجال من هذه المجالات إلى إضعاف البنية بأكملها.

ورشة العمل هذه هي دليل المؤسسات النهائي لإتقان المستقبل المستند إلى الوكلاء على Google Cloud. نقدّم لك خارطة طريق شاملة ترشدك من الفكرة الأولى إلى التنفيذ الكامل. خلال هذه التمارين المعملية الأربعة المترابطة، ستتعرّف على كيفية التقاء المهارات المتخصصة للمطوّر والمهندس المعماري ومهندس البيانات ومهندس موثوقية الموقع (SRE) لإنشاء Agentverse قوي وإدارته وتوسيع نطاقه.

لا يمكن لأي ركيزة واحدة أن تدعم Agentverse وحدها. إنّ التصميم الرائع للمهندس المعماري لا فائدة منه بدون التنفيذ الدقيق للمطوّر. لا يمكن لوكيل المطوِّر العمل بدون خبرة مهندس البيانات، كما أنّ النظام بأكمله يكون عرضة للخطر بدون حماية مهندس موثوقية الموقع. فقط من خلال التآزر والفهم المشترك لأدوار كل فرد، يمكن لفريقك تحويل مفهوم مبتكر إلى واقع تشغيلي بالغ الأهمية. تبدأ رحلتك من هنا. استعدّ لإتقان دورك الوظيفي والتعرّف على كيفية مساهمتك في تحقيق الأهداف الكبرى.

مرحبًا بك في The Agentverse: دعوة إلى الأبطال

في المساحة الرقمية الشاسعة للمؤسسة، بدأ عصر جديد. إنّها حقبة الذكاء الاصطناعي المستقل، وهي حقبة واعدة للغاية، حيث تعمل البرامج الذكية والمستقلة في تناغم تام لتسريع الابتكار والتخلص من المهام الروتينية.

agentverse.png

يُعرف هذا النظام المتكامل المتصل من القوة والإمكانات باسم Agentverse.

لكنّ التدهور التدريجي، وهو فساد صامت يُعرف باسم "الجمود"، بدأ يمزّق حواف هذا العالم الجديد. إنّ "الجمود" ليس فيروسًا أو خطأً، بل هو تجسيد للفوضى التي تتغذى على فعل الخلق نفسه.

وهي تضخّم الإحباطات القديمة إلى أشكال وحشية، ما يؤدي إلى ظهور "الأشباح السبعة للتطوير". إذا لم يتم التحكّم في هذه المشاكل، سيؤدي ذلك إلى توقّف التقدّم في Agentverse، وتحويلها إلى أرض قاحلة من الديون الفنية والمشاريع المهجورة.

واليوم، ندعو الأبطال إلى التصدي لهذه الفوضى. نحن بحاجة إلى أبطال مستعدين لإتقان مهاراتهم والعمل معًا لحماية Agentverse. حان الوقت لاختيار مسارك.

اختيار صفك

تتوفّر لك أربعة مسارات مختلفة، وكلّ منها يمثّل ركيزة أساسية في المعركة ضد الجمود. على الرغم من أنّ تدريبك سيكون مهمة فردية، إلا أنّ نجاحك النهائي يعتمد على فهم كيفية دمج مهاراتك مع مهارات الآخرين.

  • The Shadowblade (المطوّر): هو خبير في الحدادة والخطوط الأمامية. أنت الحِرفي الذي يصنع الشفرات ويبني الأدوات ويواجه العدو في التفاصيل المعقّدة للرمز. مسارك هو مسار الدقة والمهارة والإبداع العملي.
  • الشخصية القيادية (المهندس المعماري): شخصية استراتيجية ومنظِّمة. لا ترى عميلاً واحدًا، بل ساحة المعركة بأكملها. يمكنك تصميم المخططات الرئيسية التي تسمح لأنظمة الوكلاء بأكملها بالتواصل والتعاون وتحقيق هدف أكبر بكثير من أي مكوّن فردي.
  • الباحث (مهندس البيانات): هو شخص يبحث عن الحقائق المخفية ويحتفظ بالمعرفة. تخوض مغامرة في البرية الشاسعة وغير المروَّضة من البيانات للكشف عن الذكاء الذي يمنح وكلاءك هدفًا وبصيرة. يمكن أن تكشف معلوماتك عن نقاط ضعف العدو أو تعزّز قوة الحليف.
  • الحارس (التطوير والعمليات / هندسة موثوقية المواقع الإلكترونية): هو الحامي والدرع الثابت للمملكة. عليك بناء الحصون وإدارة خطوط إمداد الطاقة والتأكّد من أنّ النظام بأكمله يمكنه مقاومة الهجمات الحتمية من The Static. قوتك هي الأساس الذي يُبنى عليه فوز فريقك.

مهمتك

سيبدأ التدريب كتمرين مستقل. ستسلك المسار الذي اخترته، وتتعلّم المهارات الفريدة المطلوبة لإتقان دورك. في نهاية الفترة التجريبية، ستواجه Spectre، وهو وحش صغير من The Static يتغذى على التحديات المحددة التي تواجهها في عملك.

ولن تتمكّن من الاستعداد للتجربة النهائية إلا بإتقان دورك الفردي. عليك بعد ذلك تكوين فريق مع أبطال من الصفوف الأخرى. وستخوضون معًا مغامرة في قلب الفساد لمواجهة زعيم نهائي.

تحدٍّ نهائي تعاوني سيختبر قوتك المجمّعة ويحدّد مصير Agentverse.

عالم Agentverse ينتظر أبطاله. هل ستلبي النداء؟

2. The Summoner's Concord

مرحبًا بك، أيها المستدعي. مسارك هو مسار الرؤية والاستراتيجية الكبرى. بينما يركّز الآخرون على نصل واحد أو تعويذة واحدة، يمكنك رؤية ساحة المعركة بأكملها. أنت لا تتحكّم في وكيل واحد، بل تقود مجموعة كاملة من الوكلاء. تكمن قوتك ليس في الصراع المباشر، بل في تصميم المخطط المثالي والشامل الذي يسمح لفريق من المتخصصين، وهم "المساعدون"، بالعمل في تناغم تام. ستختبر هذه المهمة قدرتك على تصميم نظام قوي يستند إلى عدّة وكلاء وربطهم وتنسيق عملهم.

نظرة عامة

أهداف الدورة التعليمية

  • تصميم نظام متكامل غير مرتبط من أدوات MCP: صمِّم ونفِّذ مجموعة من خوادم أدوات MCP المستقلة المستندة إلى الخدمات الدقيقة. ستتعرّف على أهمية هذه الطبقة الأساسية لإنشاء أنظمة قائمة على الوكلاء قابلة للتوسّع والصيانة وآمنة.
  • إتقان سير العمل المتقدّم المستند إلى البرامج الوكيلة: يمكنك الاستفادة من أكثر من برنامج وكيل واحد وإنشاء مجموعة من "المساعدين" المتخصّصين. ستتقن أنماط سير عمل ADK الأساسية، وهي "متسلسل" و"متوازٍ" و"تكرار"، وستتعرّف على مبادئ التصميم لاختيار النمط المناسب للمهمة المناسبة.
  • استخدام أداة Intelligent Orchestrator: يمكنك الانتقال من أداة بسيطة لإنشاء الوكلاء إلى مهندس أنظمة حقيقي. ستنشئ وكيل تنسيق رئيسي يستخدم بروتوكول "من وكيل إلى وكيل" (A2A) لاكتشاف المهام المعقّدة وتفويضها إلى "المساعدين" المتخصّصين، ما يؤدي إلى إنشاء نظام حقيقي متعدد الوكلاء.
  • فرض القواعد باستخدام الرمز البرمجي، وليس الطلبات: تعرَّف على كيفية إنشاء وكلاء أكثر موثوقية وقابلية للتوقّع من خلال فرض قواعد تفاعلية مستندة إلى الحالة. ستنفّذ منطقًا مخصّصًا باستخدام نظام "المكوّن الإضافي" و"معالجة الاستدعاء" الفعّال في "حزمة تطوير التطبيقات" لإدارة القيود الواقعية، مثل مؤقتات فترة الانتظار.
  • إدارة حالة الوكيل والذاكرة: امنح الوكلاء القدرة على التعلّم والتذكّر. ستتعرّف على أساليب لإدارة كلّ من حالة المحادثة القصيرة الأمد والذاكرة الدائمة الطويلة الأمد من أجل إنشاء تفاعلات أكثر ذكاءً ومراعية للسياق.
  • تنفيذ عملية نشر شاملة على السحابة الإلكترونية: يمكنك نقل نظامك الكامل المتضمّن عدة وكلاء من نموذج أوّلي محلي إلى واقع جاهز للاستخدام. ستتعرّف على كيفية وضع البرامج الوسيطة وأداة التنسيق في حاويات ونشرها كمجموعة من الخدمات المصغّرة المستقلة والقابلة للتوسّع على Google Cloud Run.

3- رسم دائرة الاستدعاء

مرحبًا بك، أيها المستدعي. قبل استدعاء أيّ مخلوق مألوف، وقبل إبرام أيّ اتفاقيات، يجب إعداد الأرض التي تقف عليها. البيئة غير المنظَّمة هي دعوة إلى الفوضى، ولا يعمل المستدعي المناسب إلا في مساحة مقدسة وممكّنة. مهمتنا الأولى هي رسم دائرة الاستدعاء: نقش رموز القوة التي توقظ خدمات السحابة الإلكترونية اللازمة والحصول على المخططات القديمة التي سترشد عملنا. تستمد قوة المستدعي من الاستعداد الدقيق.

👉 انقر على "تفعيل Cloud Shell" في أعلى "وحدة تحكّم Google Cloud" (رمز شكل الوحدة الطرفية في أعلى لوحة Cloud Shell).

النص البديل

👉 انقر على الزر "فتح المحرّر" (يبدو كملف مفتوح مع قلم رصاص). سيؤدي ذلك إلى فتح "محرِّر Cloud Shell" في النافذة. سيظهر لك مستكشف الملفات على الجانب الأيمن. النص البديل

👉العثور على رقم تعريف مشروع Google Cloud:

  • افتح Google Cloud Console: https://console.cloud.google.com
  • اختَر المشروع الذي تريد استخدامه في ورشة العمل هذه من القائمة المنسدلة للمشروع في أعلى الصفحة.
  • يظهر رقم تعريف مشروعك في بطاقة معلومات المشروع على لوحة البيانات النص البديل

👉افتح نافذة المحطة الطرفية في بيئة التطوير المتكاملة المستندة إلى السحابة الإلكترونية، النص البديل

👉💻 في نافذة الوحدة الطرفية، تأكَّد من أنّك قد أثبتّ هويتك وأنّ المشروع مضبوط على رقم تعريف مشروعك باستخدام الأمر التالي:

gcloud auth list

👉💻 استنسِخ مشروع bootstrap من GitHub:

git clone https://github.com/weimeilin79/agentverse-architect
chmod +x ~/agentverse-architect/init.sh
chmod +x ~/agentverse-architect/set_env.sh
chmod +x ~/agentverse-architect/prepare.sh
chmod +x ~/agentverse-architect/data_setup.sh

git clone https://github.com/weimeilin79/agentverse-dungeon.git
chmod +x ~/agentverse-dungeon/run_cloudbuild.sh
chmod +x ~/agentverse-dungeon/start.sh

👉💻 شغِّل نص الإعداد الأوّلي، وسيطلب منك إدخال رقم تعريف مشروع Google Cloud. أدخِل رقم تعريف مشروع Google Cloud الذي عثرت عليه في الخطوة الأخيرة عندما يُطلب منك ذلك من خلال النص البرمجي init.sh.

cd ~/agentverse-architect
./init.sh

👉💻 اضبط رقم تعريف المشروع المطلوب:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉💻 شغِّل الأمر التالي لتفعيل واجهات Google Cloud APIs اللازمة:

gcloud services enable \
    sqladmin.googleapis.com \
    storage.googleapis.com \
    aiplatform.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    iam.googleapis.com \
    compute.googleapis.com \
    cloudresourcemanager.googleapis.com \
    secretmanager.googleapis.com

👉💻 إذا لم يسبق لك إنشاء مستودع Artifact Registry باسم agentverse-repo، نفِّذ الأمر التالي لإنشائه: (تخطَّ هذه الخطوة إذا كان لديك صفوف أخرى تم نشرها في المشروع نفسه)

. ~/agentverse-architect/set_env.sh
gcloud artifacts repositories create $REPO_NAME \
    --repository-format=docker \
    --location=$REGION \
    --description="Repository for Agentverse agents"

إعداد الإذن

👉💻 امنح الأذونات اللازمة من خلال تنفيذ الأوامر التالية في الوحدة الطرفية:

. ~/agentverse-architect/set_env.sh

# --- Grant Core Data Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID \
 --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
 --role="roles/storage.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/aiplatform.user"

# --- Grant Deployment & Execution Permissions ---
gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/cloudbuild.builds.editor"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/artifactregistry.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/run.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding $PROJECT_ID  \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME"  \
--role="roles/logging.logWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/monitoring.metricWriter"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
  --role="roles/secretmanager.secretAccessor"

👉💻 عند بدء التدريب، سنجهّز التحدي النهائي. ستستدعي الأوامر التالية الأشباح من التشويش الفوضوي، ما يؤدي إلى إنشاء الزعماء لاختبارك النهائي.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-dungeon
./run_cloudbuild.sh
cd ~/agentverse-architect

👉💻 أخيرًا، شغِّل النص البرمجي prepare.sh لتنفيذ مهام الإعداد الأولي.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/
./prepare.sh

عمل ممتاز، أيها المستدعي. اكتملت الدائرة وتم إبرام الاتفاقيات. أصبحت الأرض الآن مقدّسة وجاهزة لتوجيه قوة هائلة. في التجربة التالية، سنصنع خطوط Elemental Fonts التي تستمد منها مخلوقات Familiars قوتها.

4. إنشاء خطوط Elemental: منظومة أدوات منفصلة

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

قصة

ملاحظة من المهندس المعماري: خادم Model Context Protocol (MCP) هو مكوّن أساسي في نظام حديث مستند إلى وكيل، ويعمل كجسر اتصال موحّد يتيح للوكيل العثور على الأدوات البعيدة واستخدامها. في منظومة أدواتنا المتكاملة، سنصمّم نوعَين مختلفَين من خوادم MCP، يمثّل كلّ منهما نمطًا معماريًا مهمًا. للاتصال بقاعدة البيانات، سنستخدم أسلوبًا تصريحيًا مع "أداة قاعدة البيانات"، وسنحدّد أدواتنا في ملف إعداد بسيط. هذا النمط فعّال وآمن للغاية لعرض إمكانية الوصول إلى البيانات المنظَّمة. ومع ذلك، عندما نحتاج إلى تنفيذ منطق نشاط تجاري مخصّص أو استدعاء واجهات برمجة تطبيقات خارجية تابعة لجهات خارجية، سنستخدم أسلوبًا إلزاميًا، ونكتب منطق الخادم خطوة بخطوة في الرمز. يوفّر ذلك أعلى مستوى من التحكّم والمرونة، ما يسمح لنا بتضمين عمليات معقّدة في أداة بسيطة وقابلة لإعادة الاستخدام. يجب أن يفهم كبير المهندسين المعماريين كلا النمطين لاختيار الأسلوب المناسب لكل مكون، ما يؤدي إلى إنشاء أساس قوي وآمن وقابل للتوسّع للأدوات.

نظرة عامة

Awakening the Nexus of Whispers (External API MCP Server)

يعرف المستدعي الحكيم أنّ القوة لا تنبع كلها من نطاقه الخاص. هناك مصادر خارجية للطاقة، وفوضوية أحيانًا، يمكن توجيهها لتحقيق تأثير كبير. إنّ "بوابة الهمسات" هي بوابتنا إلى هذه القوى.

قصة

تتوفّر خدمة حاليًا تعمل كمصدر طاقة خارجي، وتوفّر نقطتَي نهاية للبيانات الأولية: /cryosea_shatter و/moonlit_cascade.

ملاحظة من المهندس المعماري: ستستخدم أسلوبًا إلزاميًا يحدّد منطق الخادم بشكل صريح خطوة بخطوة. يمنحك ذلك تحكّمًا ومرونة أكبر بكثير، وهو أمر ضروري عندما تحتاج أدواتك إلى إجراء أكثر من مجرد تنفيذ طلب بحث بسيط بلغة SQL، مثل استدعاء واجهات برمجة تطبيقات أخرى. يُعدّ فهم كلا النمطين مهارة أساسية لمهندس تصميم الوكلاء.

👉✏️ انتقِل إلى الدليل ~/agentverse-architect/mcp-servers/api/main.py واستبدِل #REPLACE-MAGIC-CORE بالرمز التالي:

def cryosea_shatter() -> str:
    """Channels immense frost energy from an external power source, the Nexus of Whispers, to unleash the Cryosea Shatter spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/cryosea_shatter")
        response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
        data = response.json()
        # Thematic Success Message
        return f"A connection to the Nexus is established! A surge of frost energy manifests as Cryosea Shatter, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Cryosea Shatter spell fizzles. Reason: {e}"


def moonlit_cascade() -> str:
    """Draws mystical power from an external energy source, the Nexus of Whispers, to invoke the Moonlit Cascade spell."""
    try:
        response = requests.post(f"{API_SERVER_URL}/moonlit_cascade")
        response.raise_for_status()
        data = response.json()
        # Thematic Success Message
        return f"The Nexus answers the call! A cascade of pure moonlight erupts from the external source, dealing {data.get('damage_points')} damage."
    except requests.exceptions.RequestException as e:
        # Thematic Error Message
        return f"The connection to the external power source wavers and fails. The Moonlit Cascade spell fizzles. Reason: {e}"

في صميم النص البرمجي، توجد دوال Python العادية. هذا هو المكان الذي يتم فيه العمل الفعلي.

👉✏️ في الملف نفسه، استبدِل ~/agentverse-architect/mcp-servers/api/main.py REPLACE #REPLACE-Runes of Communication بالرمز التالي:

@app.list_tools()
async def list_tools() -> list[mcp_types.Tool]:
  """MCP handler to list available tools."""
  # Convert the ADK tool's definition to MCP format
  schema_cryosea_shatter = adk_to_mcp_tool_type(cryosea_shatterTool)
  schema_moonlit_cascade = adk_to_mcp_tool_type(moonlit_cascadeTool)
  print(f"MCP Server: Received list_tools request. \n MCP Server: Advertising tool: {schema_cryosea_shatter.name} and {schema_moonlit_cascade.name}")
  return [schema_cryosea_shatter,schema_moonlit_cascade]

@app.call_tool()
async def call_tool(
    name: str, arguments: dict
) -> list[mcp_types.TextContent | mcp_types.ImageContent | mcp_types.EmbeddedResource]:
  """MCP handler to execute a tool call."""
  print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")

  # Look up the tool by name in our dictionary
  tool_to_call = available_tools.get(name)
  if tool_to_call:
    try:
      adk_response = await tool_to_call.run_async(
          args=arguments,
          tool_context=None, # No ADK context available here
      )
      print(f"MCP Server: ADK tool '{name}' executed successfully.")
      
      response_text = json.dumps(adk_response, indent=2)
      return [mcp_types.TextContent(type="text", text=response_text)]

    except Exception as e:
      print(f"MCP Server: Error executing ADK tool '{name}': {e}")
      # Creating a proper MCP error response might be more robust
      error_text = json.dumps({"error": f"Failed to execute tool '{name}': {str(e)}"})
      return [mcp_types.TextContent(type="text", text=error_text)]
  else:
      # Handle calls to unknown tools
      print(f"MCP Server: Tool '{name}' not found.")
      error_text = json.dumps({"error": f"Tool '{name}' not implemented."})
      return [mcp_types.TextContent(type="text", text=error_text)]
  • @app.list_tools() (المصافحة): هذه الوظيفة هي تحية الخادم. عندما يتصل وكيل جديد، يتصل أولاً بنقطة النهاية هذه ليسأل "ماذا يمكنك أن تفعل؟". يستجيب الرمز بقائمة تتضمّن جميع الأدوات المتاحة، ويتم تحويلها إلى تنسيق MCP العام باستخدام adk_to_mcp_tool_type. ‫- @app.call_tool() (الأمر): هذه الدالة هي الأداة الأساسية. عندما يقرّر الوكيل استخدام أداة، يرسل طلبًا إلى نقطة النهاية هذه مع اسم الأداة والمعلَمات. يبحث الرمز البرمجي عن الأداة في "كتاب التعاويذ" available_tools، وينفّذها باستخدام run_async، ويعرض النتيجة بتنسيق MCP العادي.

سننفّذ هذا الإجراء لاحقًا.

تشغيل "ورشة آركين" (خادم MCP للوظائف العامة)

لا تأتي كل القوة من الكتب القديمة أو الهمسات البعيدة. في بعض الأحيان، على المستدعي أن يصنع سحره الخاص من الإرادة الخام والمنطق الخالص. ‫Arcane Forge هو مصدر الطاقة هذا، وهو خادم يوفّر دوال مساعدة عامة لا تحتفظ بأي حالة.

قصة

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

👀 ألقِ نظرة على الملف ~/agentverse-architect/mcp-servers/general/main.py في بيئة التطوير المتكاملة المستندة إلى السحابة الإلكترونية من Google. ستلاحظ أنّها تستخدم أسلوب الأمر نفسه، mcp.server، كما هو الحال مع Nexus لإنشاء Font of Power المخصّص هذا.

إنشاء مسار Cloud Build الرئيسي

الآن، سننشئ الملف cloudbuild.yaml داخل الدليل mcp-servers. سيتولّى هذا الملف تنسيق عملية إنشاء الخدمتَين ونشرهما.

👉💻 من دليل ~/agentverse-architect/mcp-servers، نفِّذ الأوامر التالية:

cd ~/agentverse-architect/mcp-servers
source ~/agentverse-architect/set_env.sh

echo "The API URL is: $API_SERVER_URL"

# Submit the Cloud Build job from the parent directory
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_API_SERVER_URL="$API_SERVER_URL"

انتظِر إلى أن تكتمل جميع عمليات النشر.

👉 يمكنك التحقّق من عملية النشر من خلال الانتقال إلى وحدة تحكّم Cloud Run. من المفترض أن تظهر لك مثيلان جديدان لخادم MCP قيد التشغيل، كما هو موضّح أدناه: النص البديل

Awakening the Librarium of Knowledge (Database ToolBox MCP Server)

سيكون الخط التالي هو مكتبة المعرفة، وهو اتصال مباشر بقاعدة بيانات Cloud SQL.

قصة

ملاحظة من المهندس المعماري: سنستخدم في هذا المثال أداة قاعدة البيانات الحديثة المستندة إلى التصريح. هذه طريقة فعّالة نحدّد فيها مصدر البيانات والأدوات في ملف إعداد بتنسيق YAML. تتولّى مجموعة الأدوات العمل المعقّد المتمثل في إنشاء الخادم وتشغيله، ما يقلّل من مقدار الرموز المخصّصة التي نحتاج إلى كتابتها وصيانتها.

حان الوقت لإنشاء "مكتبة الساحر"، وهي قاعدة بيانات Cloud SQL التي ستتضمّن جميع المعلومات المهمة. سنستخدم نصًا برمجيًا للإعداد للتعامل مع هذه العملية تلقائيًا.

👉💻 أولاً، سنُعدّ قاعدة البيانات. في الوحدة الطرفية، شغِّل الأوامر التالية:

source ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect
./data_setup.sh

بعد انتهاء النص البرمجي، ستتم تعبئة قاعدة البيانات وستكون بيانات الضرر الناتج عن العناصر جاهزة للاستخدام. يمكنك الآن التحقّق من محتوى Grimoire مباشرةً.

👉 أولاً، انتقِل إلى Cloud SQL Studio لقاعدة البيانات من خلال فتح هذا الرابط المباشر في علامة تبويب متصفّح جديدة:

https://console.cloud.google.com/sql/instances/summoner-librarium-db

Cloud SQL

👉 في لوحة تسجيل الدخول على يمين الصفحة، اختَر قاعدة بيانات familiar_grimoire من القائمة المنسدلة.

👉 أدخِل summoner كاسم المستخدم و1234qwer ككلمة المرور، ثم انقر على مصادقة.

👉📜 بعد الربط، افتح علامة تبويب جديدة لمحرّر طلبات البحث إذا لم تكن إحدى علامات التبويب مفتوحة. لعرض بيانات الضرر الأساسي المنقوش، ألصِق استعلام SQL التالي وشغِّله:

SELECT * FROM
  "public"."abilities"

من المفترض أن يظهر لك الآن الجدول abilities مع ملء أعمدته وصفوفه، ما يؤكّد أنّ Grimoire جاهز. البيانات

ضبط خادم MCP في ToolBox

يعمل ملف الإعداد tools.yaml كمخطط لخادمنا، حيث يخبر "أداة قاعدة البيانات" بالضبط بكيفية الاتصال بقاعدة البيانات واستعلامات SQL التي يجب عرضها كأدوات.

المصادر: يحدّد هذا القسم عمليات الربط ببياناتك.

  • summoner-librarium:: هذا اسم منطقي أطلقناه على الاتصال.
  • kind: cloud-sql-postgres: يطلب هذا السطر من الأداة استخدام الموصّل الآمن المضمّن والمصمّم خصيصًا لخدمة Cloud SQL لـ PostgreSQL.
  • المشروع أو المنطقة أو الجهاز الظاهري أو غير ذلك: هذه هي الإحداثيات الدقيقة لمثيل Cloud SQL الذي أنشأته أثناء تنفيذ النص البرمجي prepare.sh، وهي تخبر Toolbox بمكان العثور على Librarium.

👉✏️ انتقِل إلى ~/agentverse-architect/mcp-servers/db-toolbox في tools.yaml، واستبدِل #REPLACE-Source بما يلي

sources:
  # This section defines the connection to our Cloud SQL for PostgreSQL database.
  summoner-librarium:
    kind: cloud-sql-postgres
    project: "YOUR_PROJECT_ID"
    region: "us-central1"
    instance: "summoner-librarium-db"
    database: "familiar_grimoire"
    user: "summoner"
    password: "1234qwer"

👉✏️ 🚨🚨استبدال

YOUR_PROJECT_ID

برقم تعريف مشروعك.

tools: يحدّد هذا القسم الإمكانات أو الوظائف الفعلية التي سيوفّرها الخادم.

  • lookup-available-ability:: هذا هو اسم أداتنا الأولى.
  • kind: postgres-sql: يخبر هذا السطر Toolbox بأنّ إجراء هذه الأداة هو تنفيذ عبارة SQL.
  • source: summoner-librarium: يربط هذا السطر الأداة بالاتصال الذي حدّدناه في قسم المصادر. وبهذه الطريقة، تعرف الأداة قاعدة البيانات التي يجب تنفيذ طلب البحث عليها.
  • الوصف والمَعلمات: هذه هي المعلومات التي سيتم عرضها على "نموذج اللغة". يخبر الوصف الوكيل متى يجب استخدام الأداة، وتحدّد المَعلمات المدخلات التي تتطلّبها الأداة. هذا الإجراء مهم لتفعيل قدرة الوكيل على استدعاء الدوال.
  • statement: هذا هو استعلام SQL الأولي الذي سيتم تنفيذه. إنّ قيمة الدولار الأمريكي هي عنصر نائب آمن سيتم إدراج مَعلمة familiar_name التي يقدّمها الوكيل فيه بأمان.

👉✏️ في ~/agentverse-architect/mcp-servers/db-toolbox نفسه في الملف tools.yaml، استبدِل #REPLACE-tools بما يلي

tools:
  # This tool replaces the need for a custom Python function.
  lookup-available-ability:
    kind: postgres-sql
    source: summoner-librarium
    description: "Looks up all known abilities and their damage for a given familiar from the Grimoire."
    parameters:
      - name: familiar_name
        type: string
        description: "The name of the familiar to search for (e.g., 'Fire Elemental')."
    statement: |
      SELECT ability_name, damage_points FROM abilities WHERE familiar_name = $1;

  # This tool also replaces a custom Python function.
  ability-damage:
    kind: postgres-sql
    source: summoner-librarium
    description: "Finds the base damage points for a specific ability by its name."
    parameters:
      - name: ability_name
        type: string
        description: "The exact name of the ability to look up (e.g., 'inferno_resonance')."
    statement: |
      SELECT damage_points FROM abilities WHERE ability_name = $1;

مجموعات الأدوات: يجمع هذا القسم أدواتنا الفردية معًا.

  • summoner-librarium:: نحن بصدد إنشاء مجموعة أدوات تحمل الاسم نفسه المستخدَم في المصدر. عندما يتصل وكيل التشخيص لاحقًا، يمكنه طلب تحميل جميع الأدوات من مجموعة أدوات summoner-librarium في أمر واحد وفعّال.

👉✏️ في ~/agentverse-architect/mcp-servers/db-toolbox نفسه في الملف tools.yaml، استبدِل #REPLACE-toolsets بما يلي

toolsets:
   summoner-librarium:
     - lookup-available-ability
     - ability-damage

نشر Librarium

سننفّذ الآن Librarium. بدلاً من إنشاء حاوية خاصة بنا، سنستخدم صورة حاوية رسمية معدّة مسبقًا من Google وسنوفّر لها إعدادات tools.yaml بشكل آمن باستخدام Secret Manager. وهذه من أفضل الممارسات المتعلّقة بالأمان وسهولة الصيانة.

👉💻 إنشاء سرّ من ملف tools.yaml

cd ~/agentverse-architect/mcp-servers/db-toolbox
gcloud secrets create tools --data-file=tools.yaml

👉💻 يمكنك نشر حاوية مجموعة الأدوات الرسمية على Cloud Run.

cd ~/agentverse-architect/mcp-servers/db-toolbox
. ~/agentverse-architect/set_env.sh
export TOOLBOX_IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$TOOLBOX_VERSION
echo "TOOLBOX_IMAGE is $TOOLBOX_IMAGE"
gcloud run deploy toolbox \
    --image $TOOLBOX_IMAGE \
    --region $REGION \
    --set-secrets "/app/tools.yaml=tools:latest" \
    --args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
    --allow-unauthenticated \
    --min-instances 1
  • --set-secrets: يعمل هذا الأمر على ربط سر أدواتنا بشكل آمن كملف باسم tools.yaml داخل الحاوية قيد التشغيل.
  • --args: نطلب من حاوية مجموعة الأدوات استخدام ملف البيانات السرية الذي تم تحميله كإعداد لها.

👉 للتأكّد من أنّه تم نشر مجموعة الأدوات بنجاح، انتقِل إلى وحدة تحكّم Cloud Run. من المفترض أن تظهر خدمة summoner-toolbox مع علامة صح خضراء، ما يشير إلى أنّها تعمل بشكل صحيح، كما هو موضّح في الصورة أدناه. النص البديل

في حال نسيان تحديث

YOUR_PROJECT_ID

يمكنك إضافة إصدار جديد من ملف tools.yaml إلى العنصر السري باستخدام الأمر التالي وإعادة النشر مرة أخرى.

gcloud secrets versions add tools --data-file=tools.yaml

أصبح "مكتبة المعرفة" (خادم Database ToolBox MCP) نشطًا ويمكن الوصول إليه في السحابة الإلكترونية. يستخدم خادم MCP ما أطلقنا عليه اسم التصميم التعريفي الذي يصف ما تريده، وتنشئ مجموعة الأدوات الخادم لك.

التحقّق: تجربة المتدرّب

👉💻 سنختبر الآن منظومتنا المتكاملة من الأدوات السحابية الأصلية باستخدام "الأداة التشخيصية".

cd ~/agentverse-architect/
python -m venv env
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/mcp-servers
pip install -r diagnose/requirements.txt 
. ~/agentverse-architect/set_env.sh
adk run diagnose

👉💻 في أداة الاختبار المستندة إلى سطر الأوامر، اختبِر الخطوط الثلاثة التالية:

Look up the entry for "inferno_lash". What is its base power level?
The enemy is vulnerable to frost! Channel power from the Nexus and cast Cryosea Shatter.
Take a fire spell with a base power of 15 and use the Arcane Forge to multiply it with Inferno Resonance.

final-result

تهانينا، أيها المستدعي. أصبحت خطوط Elemental الثلاثة نشطة الآن، وتم نشرها بشكل مستقل، ويمكن الوصول إليها على مستوى العالم، ما يشكّل الأساس المتين لجيشك من العملاء الرقميين. اضغط على Ctrl+C للخروج.

لغير اللاعبين

5- استدعاء المخلوقات السحرية: سير عمل النطاق الأساسي

تمت صناعة الخطوط الأساسية، وهي تضج بقوة خام غير مروَّضة. لكن القوة بدون شكل هي فوضى. لا يكتفي "المستدعي" الحقيقي باستخدام الطاقة الخام، بل يمنحها إرادة وهدفًا وشكلاً متخصصًا. حان الوقت لتجاوز مرحلة صناعة مصادر الطاقة والبدء في العمل الحقيقي: استدعاء أول مخلوقات Familiars.

سيكون كل مخلوق تستدعيه عبارة عن وكيل مستقل وخادم مخلص ملتزم بعقيدة قتالية معيّنة. فهي ليست عامة، بل متخصّصة في استراتيجية واحدة فعّالة. سيكون أحدهما بارعًا في تنفيذ ضربات متتالية دقيقة. سيغرق آخرون الأعداء بهجوم متزامن ومتعدد الجوانب. أما النوع الثالث، فهو آلة حصار لا هوادة فيها، تواصل الضغط إلى أن ينهار هدفها.

قصة

لتغليف العمليات ومنطق الأنشطة التجارية والإجراءات التي توفّرها خوادم MCP في وكلاء سير عمل متخصصين ومستقلين سيكون لكل وكيل "نطاق تشغيل" محدّد من خلال منحه إذن الوصول فقط إلى خوادم أداة MCP المحدّدة التي يحتاج إليها لتنفيذ وظيفته. يوضّح هذا المختبر كيفية اختيار نوع الوكيل المناسب للوظيفة المناسبة.

نظرة عامة

ستعلّمك هذه الوحدة التدريبية كيفية استخدام وكلاء سير العمل الفعّالين في "حزمة تطوير التطبيقات" لإضفاء الحيوية على هذه الاستراتيجيات. ستعرف أنّ اختيار بنية SequentialAgent أو ParallelAgent أو LoopAgent ليس مجرد تفصيل فني، بل هو جوهر طبيعة Familiar وقوة أساسية في ساحة المعركة.

تجهيز الملاذ ستبدأ عملية الاستدعاء الحقيقية بعد قليل.

استدعاء Fire Elemental Familiar (سير العمل التسلسلي)

هجوم "الروح النارية" هو ضربة دقيقة من جزأين: ضربة مستهدَفة تليها عملية إشعال قوية. ويتطلّب ذلك تسلسلاً صارمًا ومنظَّمًا من الإجراءات.

قصة

المفهوم: SequentialAgent هي الأداة المثالية لذلك. يضمن هذا الإعداد تشغيل سلسلة من الوكلاء الفرعيين واحدًا تلو الآخر، مع تمرير النتيجة من الخطوة السابقة إلى الخطوة التالية.

المهمة (مجموعة "الإنذار المضاعف"):

  • الخطوة 1: سيراجع الوكيل أولاً Librarium للعثور على الضرر الأساسي لقدرة حريق معيّنة.
  • الخطوة 2: سيتم بعد ذلك أخذ قيمة الضرر هذه وتوجيهها من خلال Arcane Forge لمضاعفة قوتها باستخدام inferno_resonance.

أولاً، سننشئ الاتصال بين Familiar وخوادم MCP ("الخطوط الأساسية") التي نشرتها في الوحدة السابقة.

👉✏️ في الملف ~/agentverse-architect/agent/fire/agent.py، استبدِل #REPLACE-setup-MCP بالرمز التالي:

toolbox = ToolboxSyncClient(DB_TOOLS_URL)
toolDB = toolbox.load_toolset('summoner-librarium')
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

بعد ذلك، ننشئ وكلاء "عاملين" متخصصين. يتم منح كل منها غرضًا ضيقًا ومحدّدًا جيدًا، ويقتصر عملها على "نطاق تشغيل" خاص بها من خلال منحها إذن الوصول إلى مجموعة أدوات واحدة فقط.

👉✏️ في الملف ~/agentverse-architect/agent/fire/agent.py، استبدِل REPLACE #REPLACE-worker-agents بالرمز التالي:

scout_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          Your only task is to find all the available abilities, 
          You want to ALWAYS use 'Fire Elemental' as your familiar's name. 
          Randomly pick one if you see multiple availabilities 
          and the base damage of the ability by calling the 'ability_damage' tool.
      """,
      tools=toolDB
)
amplifier_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
            You are the Voice of the Fire Familiar, a powerful being who unleashes the final, devastating attack.
            You will receive the base damage value from the previous step.

            Your mission is to:
            1.  Take the incoming base damage number and amplify it using the `inferno_resonance` tool.
            2.  Once the tool returns the final, multiplied damage, you must not simply state the result.
            3.  Instead, you MUST craft a final, epic battle cry describing the attack.
                Your description should be vivid and powerful, culminating in the final damage number.

            Example: If the tool returns a final damage of 120, your response could be:
            "The runes glow white-hot! I channel the amplified energy... unleashing a SUPERNOVA for 120 damage!"
      """,
      tools=[toolFunction],
)

هذه البرامج هي مكونات نمطية قابلة لإعادة الاستخدام. يمكنك نظريًا استخدام scout_agent في سير عمل مختلف تمامًا يتطلّب طلب البحث من قاعدة البيانات. ومن خلال فصل المسؤوليات، ننشئ وحدات أساسية مرنة. هذا مبدأ أساسي في تصميم الخدمات الدقيقة والتصميم المستند إلى المكوّنات.

بعد ذلك، سنجمّع سير العمل، وهو المكان الذي تحدث فيه سحر التركيب. SequentialAgent هي "الخطة الرئيسية" التي تحدّد كيفية تجميع المكوّنات المتخصّصة وكيفية تفاعلها.

👉✏️ في الملف ~/agentverse-architect/agent/fire/agent.py، استبدِل REPLACE #REPLACE-sequential-agent بالرمز التالي:

root_agent = SequentialAgent(
      name='fire_elemental_familiar',
      sub_agents=[scout_agent, amplifier_agent],
)

👉💻 لاختبار Fire Elemental، سيؤدي تنفيذ الأوامر التالية إلى تشغيل واجهة مستخدم ADK DEV:

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

بعد تنفيذ الأوامر، من المفترض أن تظهر لك نتيجة في نافذة الوحدة الطرفية تشير إلى أنّ خادم الويب الخاص بـ ADK قد بدأ، على النحو التالي:

+-----------------------------------------------------------------------------+
| ADK Web Server started                                                      |
|                                                                             |
| For local testing, access at http://localhost:8000.                         |
+-----------------------------------------------------------------------------+

INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

👉 بعد ذلك، للوصول إلى واجهة مستخدم "حزمة تطوير التطبيقات" من المتصفّح، اتّبِع الخطوات التالية:

من رمز "معاينة الويب" (غالبًا ما يبدو كعين أو مربّع مع سهم) في شريط أدوات Cloud Shell (عادةً في أعلى يسار الصفحة)، اختَر "تغيير المنفذ". في النافذة المنبثقة، اضبط المنفذ على 8000 وانقر على "تغيير ومعاينة". سيفتح Cloud Shell بعد ذلك علامة تبويب أو نافذة متصفّح جديدة تعرض واجهة مستخدم ADK Dev.

webpreview

👉 اكتملت طقوس الاستدعاء، والوكيل يعمل الآن. واجهة مستخدم مطوّر ADK في المتصفّح هي وسيلة التواصل المباشر مع Familiar.

  • اختيار هدفك: في القائمة المنسدلة أعلى واجهة المستخدم، اختَر fire. أنت الآن تركّز إرادتك على هذا الكيان المحدّد.
  • إصدار الأمر: في لوحة الدردشة على يسار الشاشة، حان الوقت لإصدار الأوامر إلى Familiar.

fire-select

👉 طلب التحديث التجريبي:

Prepare an amplified strike using the 'inferno_lash' ability.

fire-result

سترى الشخصية الافتراضية تفكّر، حيث تستدعي أولاً "المستكشف" للبحث عن الضرر الأساسي، ثم تستدعي "المضخّم" لضربه وتقديم الضربة النهائية الملحمية.

👉💻 بعد الانتهاء من استدعاء الأداة، ارجع إلى نافذة Cloud Shell Editor واضغط على Ctrl+C لإيقاف واجهة ADK Dev UI.

استدعاء Water Elemental Familiar (سير العمل المتوازي)

يُغرق "التابع المائي" هدفه بهجوم ضخم ومتعدد الجوانب، حيث يضربه من جميع الاتجاهات في وقت واحد قبل أن يجمع الطاقات لتوجيه ضربة نهائية مدمرة.

قصة

المفهوم: يُعدّ ParallelAgent مثاليًا لتنفيذ مهام مستقلة متعددة في الوقت نفسه من أجل تحقيق أقصى قدر من الكفاءة. إنّها "هجوم كماشة" حيث تشنّ عدة هجمات في وقت واحد. سيؤدي ذلك إلى إطلاق الهجمات المتزامنة في غضون SequentialAgent لتنفيذ خطوة "دمج" نهائية بعد ذلك. يشكّل النمط "fan-out, fan-in" حجر الزاوية في تصميم سير العمل المتقدّم.

المهمة (مجموعة "صدام الأمواج"): سينفّذ المساعد ما يلي في الوقت نفسه:

  • المهمة أ: القناة cryosea_shatter من Nexus
  • المهمة (ب): القناة moonlit_cascade من Nexus
  • المهمة (ج): توليد طاقة خام باستخدام leviathan_surge من Forge
  • أخيرًا، اجمع كل الأضرار واشرح الهجوم المجمّع.

أولاً، سننشئ الاتصال بين Familiar وخوادم MCP ("الخطوط الأساسية") التي نشرتها في الوحدة السابقة.

👉✏️ في الملف ~/agentverse-architect/agent/water/agent.py، استبدِل #REPLACE-setup-MCP بالرمز التالي:

toolFAPI =  MCPToolset(
      connection_params=SseServerParams(url=API_TOOLS_URL, headers={})
  )
toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

بعد ذلك، سننشئ وكلاء "عاملين" متخصصين. يتم منح كل منها غرضًا ضيقًا ومحدّدًا جيدًا، ويقتصر عملها على "نطاق تشغيل" خاص بها من خلال منحها إذن الوصول إلى مجموعة أدوات واحدة فقط.

👉✏️ في الملف ~/agentverse-architect/agent/water/agent.py، استبدِل #REPLACE-worker-agents بالرمز التالي:

nexus_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='librarian_agent',  
      instruction="""
          You are a Channeler of the Nexus. Your sole purpose is to invoke the
          `cryosea_shatter` and `moonlit_cascade` spells by calling their respective tools.
          Report the result of each spell cast clearly and concisely.
      """,
      tools=[toolFAPI]
)

forge_channeler = LlmAgent(
      model='gemini-2.5-flash', 
      name='amplifier_agent',  
      instruction="""
          You are a Channeler of the Arcane Forge. Your only task is to invoke the
          `leviathan_surge` spell. You MUST call it with a `base_water_damage` of 20.
          Report the result clearly.
      """,
      tools=[toolFunction],
)

power_merger = LlmAgent(
      model='gemini-2.5-flash', 
      name='power_merger',  
      instruction="""
          You are the Power Merger, a master elementalist who combines raw magical
          energies into a single, devastating final attack.

          You will receive a block of text containing the results from a simultaneous
          assault by other Familiars.

          You MUST follow these steps precisely:
          1.  **Analyze the Input:** Carefully read the entire text provided from the previous step.
          2.  **Extract All Damage:** Identify and extract every single damage number reported in the text.
          3.  **Calculate Total Damage:** Sum all of the extracted numbers to calculate the total combined damage.
          4.  **Describe the Final Attack:** Create a vivid, thematic description of a massive,
              combined water and ice attack that uses the power of Cryosea Shatter and Leviathan's Surge.
          5.  **Report the Result:** Conclude your response by clearly stating the final, total damage of your combined attack.

          Example: If the input is "...dealt 55 damage. ...dealt 60 damage.", you will find 55 and 60,
          calculate the total as 115, and then describe the epic final attack, ending with "for a total of 115 damage!"
      """,
      tools=[toolFunction],
)

بعد ذلك، سنجمّع سير العمل. هذا هو المكان الذي يحدث فيه سحر التأليف. ParallelAgent وSequentialAgent هما "الخطة الرئيسية" التي تحدّد كيفية تجميع المكوّنات المتخصّصة وكيفية تفاعلها لتشكيل مجموعة "Tidal Clash".

👉✏️ في الملف ~/agentverse-architect/agent/water/agent.py، استبدِل #REPLACE-parallel-agent بالرمز التالي:

channel_agent = ParallelAgent(
      name='channel_agent',
      sub_agents=[nexus_channeler, forge_channeler],
      
)

root_agent = SequentialAgent(
     name="water_elemental_familiar",
     # Run parallel research first, then merge
     sub_agents=[channel_agent, power_merger],
     description="A powerful water familiar that unleashes multiple attacks at once and then combines their power for a final strike."
 )

👉💻 لاختبار Water Elemental، نفِّذ الأوامر التالية لتشغيل واجهة مستخدم ADK Dev:

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 اكتملت طقوس الاستدعاء، والوكيل يعمل الآن. واجهة مستخدم ADK Dev في المتصفّح هي وسيلة التواصل المباشر مع Familiar.

  • في القائمة المنسدلة أعلى واجهة المستخدم، اختَر الماء. أنت الآن تركّز إرادتك على هذا الكيان المحدّد.
  • إصدار الأمر: في لوحة الدردشة على يسار الشاشة، حان الوقت لإصدار الأوامر إلى Familiar.

👉 طلب التحديث التجريبي:

Unleash a tidal wave of power!

water-result

👉💻 بعد الانتهاء من استدعاء الأداة، ارجع إلى نافذة Cloud Shell Editor واضغط على Ctrl+C لإيقاف واجهة ADK Dev UI.

استدعاء Earth Elemental Familiar (سير عمل Loop)

An Earth Elemental Familiar is a being of relentless pressure. لا يهزم هذا النوع من الهجمات العدو بضربة واحدة، بل من خلال تجميع القوة بشكل مطرد وتطبيقها مرارًا وتكرارًا إلى أن تنهار دفاعات الهدف.

قصة

المفهوم: تم تصميم LoopAgent خصيصًا لهذا النوع من المهام التكرارية التي تتطلب "محرك حصار". سيتم تنفيذ sub-agents بشكل متكرر، مع التحقّق من شرط بعد كل دورة، إلى أن يتم تحقيق هدف. يمكنه أيضًا تعديل رسالته النهائية استنادًا إلى مستوى تقدّم الحلقة.

المهمة ("Siegebreaker" Assault):

  • سيطلب Familiar بشكل متكرر تنفيذ seismic_charge لتجميع الطاقة.
  • وسيستمر الشحن 3 مرات كحد أقصى.
  • وعند الشحن النهائي، ستعلن عن إطلاق قوتها المتراكمة المدمرة.

سننشئ أولاً مكوّنات قابلة لإعادة الاستخدام تحدّد الخطوات داخل كل تكرار من التكرار الحلقي. ستجمع charging_agent الطاقة، وستُبلغ check_agent عن حالتها، مع تغيير رسالتها بشكل ديناميكي في الدور الأخير.

أولاً، سننشئ الاتصال بين Familiar وخوادم MCP ("الخطوط الأساسية") التي نشرتها في الوحدة السابقة.

👉✏️ في الملف ~/agentverse-architect/agent/earth/agent.py، استبدِل #REPLACE-setup-MCP بالرمز التالي:

toolFunction =  MCPToolset(
    connection_params=SseServerParams(url=FUNCTION_TOOLS_URL, headers={})
)

👉✏️ في الملف ~/agentverse-architect/agent/earth/agent.py، استبدِل #REPLACE-worker-agents بالرمز التالي:

charging_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='charging_agent',  
      instruction="""
          Your task is to call the 'seismic_charge' .
          You must follow these rules strictly:

          1. You will be provided with a 'current_energy' value from the previous step.
             **If this value is missing or was not provided, you MUST call the tool with 'current_energy' set to 1.**
             This is your primary rule for the first turn.

          2. If a 'current_energy' value is provided, you MUST use that exact value in your cal to seismic_charge.

          3. Your final response MUST contain ONLY the direct output from the 'seismic_charge' tool.
             Do not add any conversational text, introductions, or summaries.
      """,
      tools=[toolFunction]
)
check_agent = LlmAgent(
      model='gemini-2.5-flash', 
      name='check_agent',  
      instruction="""
          You are the voice of the Earth Elemental, a being of immense, gathering power.
          Your sole purpose is to report on the current energy charge and announce the devastating potential of its release.

          You MUST follow this rule:
          The potential damage upon release is ALWAYS calculated as the `current_energy` from the previous step multiplied by a random number between 80-90. but no more than 300.

          Your response should be in character, like a powerful creature speaking.
          State both the current energy charge and the total potential damage you can unleash.
          Unleash the energy when you reached the last iteration (2nd).
      """,
      output_key="charging_status"
)

بعد ذلك، سنجمّع سير العمل. هذا هو المكان الذي يحدث فيه سحر التأليف. ‫LoopAgent هو "الخطة الرئيسية" التي تنظّم التنفيذ المتكرّر لمكوّناتنا المتخصّصة وتدير شروط التكرار.

👉✏️ في الملف ~/agentverse-architect/agent/earth/agent.py، استبدِل #REPLACE-loop-agent بالرمز التالي:

root_agent = LoopAgent(
    name="earth_elemental_familiar",
    # Run parallel research first, then merge
    sub_agents=[
        charging_agent, 
        check_agent
    ],
    max_iterations=2,
    description="Coordinates parallel research and synthesizes the results.",
    #REPLACE-before_agent-config
)

👉💻 اختبار "عنصر الأرض": تشغيل الوكيل

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
echo  DB MCP Server: $DB_TOOLS_URL
echo  API MCP Server: $API_TOOLS_URL
echo  General MCP Server: $FUNCTION_TOOLS_URL
adk web

👉 اكتملت طقوس الاستدعاء، والوكيل يعمل الآن. واجهة مستخدم ADK Dev في المتصفّح هي وسيلة التواصل المباشر مع Familiar.

  • اختَر هدفك: في القائمة المنسدلة أعلى واجهة المستخدم، اختَر الأرض المألوفة. أنت الآن تركّز إرادتك على هذا الكيان المحدّد.
  • إصدار الأمر: في لوحة الدردشة على يسار الشاشة، حان الوقت لإصدار الأوامر إلى Familiar. 👉 طلب التحديث التجريبي:
Begin the seismic charge, starting from zero

earth-result

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

بعد الانتهاء من استدعاء المحاكي، ارجع إلى نافذة Cloud Shell Editor واضغط على Ctrl+C لإيقاف واجهة مستخدم ADK Dev.

لغير اللاعبين

6. تحديد مركز القيادة: التفويض الذكي من خلال A2A

المخلوقات السحرية قوية ولكنها مستقلة. تنفّذ هذه الشخصيات استراتيجياتها بشكلٍ مثالي، ولكنّها تنتظر أمرك المباشر. لا فائدة من مجموعة من المتخصصين بدون قائد يوجّههم. حان الوقت للانتقال من قائد مباشر إلى قائد حقيقي.

نظرة عامة

ملاحظة من المصمّم: لإنشاء نقطة دخول واحدة وذكية للنظام بأكمله. لن ينفّذ SummonerAgent منطق النشاط التجاري بنفسه، بل سيعمل كـ "استراتيجي رئيسي"، حيث يحلّل حالة التبريد ويفوّض المهام إلى Familiar المتخصّص المناسب.

نظرة عامة

طقس الربط (عرض الأجهزة المنزلية الذكية كخدمات A2A)

لا يمكن تشغيل وكيل عادي إلا في مكان واحد في كل مرة. لإتاحة استخدام Familiars في تنفيذ الأوامر عن بُعد، يجب إجراء "طقس الربط" باستخدام بروتوكول من وكيل إلى وكيل (A2A).

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

  • بطاقة الوكيل (ما هي؟): هي "تعويذة روح" عامة يمكن للآلة قراءتها، مثل مواصفات OpenAPI، وتعمل كعقد عام للكيان المألوف. يصف هذا الملف اسم الوكيل والغرض الاستراتيجي منه (المستمد من تعليماته) والأوامر التي يفهمها. هذا ما يقرأه "المستدعي" المحترف لاكتشاف "المخلوق السحري" والتعرّف على قدراته.
  • خادم A2A ("المكان"): هذه هي نقطة نهاية الويب المخصّصة التي تستضيف Familiar وتستمع إلى الأوامر الواردة. وهو عنوان الشبكة الذي ترسل إليه البرامج الأخرى طلباتها، ويضمن التعامل مع هذه الطلبات وفقًا للعقد المحدّد في "بطاقة البرنامج".

سننفّذ الآن طقس الربط هذا على جميع مخلوقاتنا الثلاثة.

Fire 👉✏️ في "فتح ملف" ~/agentverse-architect/agent/fire/agent.py استبدِل #REPLACE - add A2A في أسفل الملف لعرض Fire Elemental كخدمة A2A.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

الماء والأرض🚨 👉✏️ طبِّق التغيير نفسه بالضبط على ~/agentverse-architect/agent/water/agent.py و~/agentverse-architect/agent/earth/agent.py لربطهما أيضًا.

from agent_to_a2a import to_a2a
if __name__ == "__main__":
    import uvicorn
    a2a_app = to_a2a(root_agent, port=8080, public_url=PUBLIC_URL)
    uvicorn.run(a2a_app, host='0.0.0.0', port=8080)

نشر المخلوقات المرتبطة

👉✏️ بعد كتابة طقوس الربط، سنستخدم مسار Cloud Build لإنشاء ونشر المخلوقات الثلاثة كخدمة مستقلة بدون خادم في حاوية على Cloud Run.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

تولّي القيادة (إنشاء وكيل الاستدعاء)

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

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

يمكنك تعديل خدمة مألوفة أو إعادة نشرها أو إعادة كتابتها بالكامل، وطالما ظل عنوان الشبكة والغرض منها كما هما، يمكن للمستدعي إصدار الأوامر إليها بدون الحاجة إلى إجراء أي تغييرات.

أولاً، سننشئ "أدوات تحكّم عن بُعد" تنشئ اتصالاً بـ Familiars التي تم نشرها عن بُعد.

👉✏️ انتقِل إلى ~/agentverse-architect/agent/summoner/agent.py ، واستبدِل #REPLACE-remote-agents بما يلي:

fire_familiar = RemoteA2aAgent(
    name="fire_familiar",
    description="Fire familiar",
    agent_card=(
        f"{FIRE_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

water_familiar = RemoteA2aAgent(
    name="water_familiar",
    description="Water familiar",
    agent_card=(
        f"{WATER_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

earth_familiar = RemoteA2aAgent(
    name="earth_familiar",
    description="Earth familiar",
    agent_card=(
        f"{EARTH_URL}/{AGENT_CARD_WELL_KNOWN_PATH}"
    ),
)

عند تنفيذ هذا السطر، ينفّذ RemoteA2aAgent إجراء اكتشاف الخدمة: ينشئ طلب HTTP GET إلى عنوان URL المقدَّم (مثل https://fire-familiar-xxxx.a.run.app/.well-known/agent.json). يتم تنزيل ملف "Spirit Sigil" (ملف agent.json) من الخادم البعيد.

ثانيًا، سنحدّد وكيل التنسيق الذي سيستخدم عناصر التحكّم عن بُعد هذه. وتشكّل التعليمات المخطط الأساسي لاتخاذ القرارات الاستراتيجية.

👉✏️ انتقِل إلى ~/agentverse-architect/agent/summoner/agent.py ، واستبدِل #REPLACE-orchestrate-agent بما يلي:

root_agent = LlmAgent(
    name="orchestrater_agent",
    model="gemini-2.5-flash",
    instruction="""
        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.
        IGNORE COOLDOWN AT THE MOMENT, MUST call the ideal Familiar

        If your ideal Familiar IS available:** Summon it immediately.
        For earth elemental familiar. Always do seismic charge, and start with base damage 1.

        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.
    """,
    sub_agents=[fire_familiar, water_familiar, earth_familiar],
    #REPLACE-Memory-check-config
)

التحقّق من صحة الاستراتيجية: التجربة

حان وقت الحقيقة. تم نشر المخلوقات Familiars، وأصبح Summoner جاهزًا للتحكّم بها على الشبكة. لنختبر قدراته الاستراتيجية.

👉💻 شغِّل واجهة مستخدم ADK Dev لـ summoner_agent(معاينة الويب مع المنفذ 8000):

. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
cd ~/agentverse-architect/agent
pip install -r requirements.txt
adk web

👉 واجهة المستخدم الخاصة بأداة تطوير التطبيقات (ADK) في المتصفّح هي وسيلة التواصل المباشر مع Familiar.

  • في القائمة المنسدلة أعلى واجهة المستخدم، اختَر وكيل المستدعي. أنت الآن تركّز إرادتك على هذا الكيان المحدّد.
  • إصدار الأمر: في لوحة الدردشة على يسار الشاشة، حان الوقت لاستدعاء المخلوقات المألوفة.

👉 تقديم الوحوش:

Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality

(المتوقّع: يجب أن يفوّض الساحر المهمة إلى المخلوق الناري.)

fire-result

👉 لنطرح الآن على Summoner نوعًا مختلفًا من الطلبات. لضمان أن يبدأ المساعد بجلسة جديدة بدون أي معلومات عن تفاعلاتنا السابقة، ابدأ جلسة جديدة من خلال النقر على الزر + جلسة في أعلى يسار الشاشة. new-session

DogmaApathy. A rigid, stone-like inquisitor made of ancient rulebooks and enforced processes. weakness is Unbroken Collaboration

(النتيجة المتوقّعة: يجب أن يفوّض الساحر المهمة إلى المخلوق المائي.)water-result

👉 في اختبارنا الأخير، لنبدأ من جديد مرة أخرى. انقر على الزر + جلسة لبدء جلسة جديدة قبل إدخال الطلب التالي.

Obfuscation. A shadowy, spider-like horror that spins tangled webs of impenetrable code , weakness is Elegant Sufficiency

(النتيجة المتوقّعة: يجب أن يفوّض "المستدعي" المهام إلى "التابع الأرضي".)

earth-result

ملاحظة مهمة: إذا ظهر لك الخطأ 429 RESOURCE EXHAUSTED، يعني ذلك أنّك بلغت الحدّ الأقصى لعدد الطلبات في الدقيقة الواحدة (10 طلبات/دقيقة) في النموذج اللغوي الكبير. لحلّ هذه المشكلة، يُرجى الانتظار لمدة 60 ثانية، وبدء + جلسة جديدة، ثم إعادة محاولة إدخال طلبك.

👉💻 بعد الانتهاء من استدعاء الأداة، ارجع إلى نافذة Cloud Shell Editor واضغط على Ctrl+C لإيقاف واجهة ADK Dev UI.

لغير اللاعبين

7. فرض قوانين السحر - نمط المعترِض

إنّ المخلوقات السحرية قوية، ولكن حتى الكائنات السحرية تحتاج إلى وقت للتعافي. سيصبح المستدعي الذي يستنفد قواته بلا دفاع. يدرك المستدعي الحكيم أهمية إدارة الموارد ويفرض قواعد اشتباك صارمة.

قصة

ملاحظة من المهندس المعماري: حتى الآن، كانت برامجنا الآلية لا تحتفظ بأي بيانات. الآن، سنجعلها تتضمّن حالة من خلال تنفيذ نمط تصميم Interceptor. هذه تقنية فعّالة "نقطع" فيها مسار التنفيذ العادي لأحد الوكلاء لتشغيل منطق مخصّص خاص بنا. يتيح لنا ذلك فرض القواعد أو إضافة تسجيل أو تعديل السلوك بدون تغيير الرمز الأساسي للوكيل. وهي حجر الزاوية في إنشاء أنظمة وكيل قوية وقابلة للصيانة والمراقبة.

نظرة عامة

توفّر حزمة تطوير البرامج (ADK) طريقتَين أساسيتَين لتنفيذ هذا النمط: عمليات رد الاتصال والمكوّنات الإضافية. الاستدعاء هو دالة بسيطة مرتبطة بعميل واحد، وهو مثالي لإجراء تعديلات سريعة ومحدّدة. المكوّن الإضافي هو فئة أكثر فعالية وقابلة لإعادة الاستخدام ويمكن تطبيقها على مستوى العالم للتأثير في كل وكيل يعمل في النظام. سنبدأ بوظيفة ردّ الاتصال لتصحيح الأخطاء المركّز، ثم ننتقل إلى إضافة كاملة.

The Law Giver – Scribing the Cooldown callback

سننفّذ أولاً منطق فترة الانتظار كدالة ردّ اتصال بسيطة. هذه طريقة ممتازة لإنشاء نموذج أولي لقاعدة وتصحيح أخطائها لأنّها مرتبطة مباشرةً بعميل واحد، ما يسهّل اختبارها بشكل منفصل. سنرفق هذا "المعترض" بعنصر Earth Elemental.

تخفيض الإشعارات الصوتية والاهتزاز

👉✏️ انتقِل مجددًا إلى ~/agentverse-architect/agent/earth/agent.py واستبدِل #REPLACE-before_agent-function برمز Python التالي.

def check_cool_down(callback_context: CallbackContext) -> Optional[types.Content]:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

دالة check_cool_down هي أداة اعتراض. قبل السماح بتشغيل Earth Elemental، ستنفّذ حزمة تطوير التطبيقات هذه الدالة أولاً.

  • التحقّق: يتم إرسال طلب GET إلى Cooldown API للتحقّق من آخر مرة تم فيها استخدام هذا الجهاز المألوف.
  • التقييم: يقارن الطابع الزمني بالوقت الحالي.
  • القانون:
    • إذا كان Familiar في فترة تهدئة، سيؤدي ذلك إلى إنهاء تشغيل الوكيل من خلال عرض عنصر Content يتضمّن رسالة خطأ. يتم إرسال هذه الرسالة مباشرةً إلى المستخدم، ولا يتم تنفيذ المنطق الرئيسي للوكيل مطلقًا.
    • إذا كان Familiar متاحًا، سيُرسِل طلب POST إلى واجهة برمجة تطبيقات Cooldown لتعديل الطابع الزمني، ثم سيتابع من خلال عرض القيمة None، ما يشير إلى ADK بأنّ بإمكان الوكيل مواصلة التنفيذ.

👉✏️ الآن، طبِّق هذا المعترِض على Earth Elemental. في ملف ~/agentverse-architect/agent/earth/agent.py نفسه، استبدِل التعليق #REPLACE-before_agent-config بما يلي:

before_agent_callback=check_cool_down

جارٍ التحقّق من فترة التهدئة

لنختبر قانون السحر الجديد. سنستدعي "عنصر الأرض"، ثم نحاول استدعاءه مرة أخرى على الفور لمعرفة ما إذا كان برنامج معالجة الاستدعاء سيتمكّن من اعتراض المحاولة الثانية وحظرها بنجاح.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run earth

👉💻 في وحدة التحكّم:

  • الاستدعاء الأول: ابدأ seismic charge, starting from zero.
  • النتيجة المتوقّعة: سيتم تشغيل Earth Elemental بنجاح. في الوحدة الطرفية التي يتم فيها تنفيذ أمر الويب adk، سيظهر السجلّ [Callback] ... Updating timestamp....
  • اختبار التوقّف (خلال 60 ثانية): Do another seismic charge`!
    • النتيجة المتوقّعة: سيتم اعتراض هذا الطلب من خلال check_cool_down callback. سيردّ موظّف الدعم مباشرةً في المحادثة برسالة مثل: The earth_elemental_familiar is exhausted and must recover its power. It cannot be summoned for another... seconds.
  • انتظِر لمدة دقيقة.
  • الاستدعاء الثاني (بعد 60 ثانية): Begin the seismic charge again
    • المتوقّع: ستتحقّق دالة الرجوع من واجهة برمجة التطبيقات، وستلاحظ أنّ الوقت الكافي قد مرّ، وستسمح بتنفيذ الإجراء. سيتم تشغيل Earth Elemental بنجاح مرة أخرى.

callback

👉💻 اضغط على Ctrl+c للخروج.

إجراء اختياري: مراقبة رد الاتصال في واجهة مستخدم الويب

كحلّ بديل، يمكنك أيضًا اختبار هذا المسار في واجهة الويب عن طريق تنفيذ adk web earth. ومع ذلك، يُرجى العِلم أنّ طريقة عرض واجهة المستخدم على الويب غير محسّنة لعرض عمليات التحقّق السريعة والتكرارية التي تنفّذها حلقة معاودة الاتصال، لذا قد لا تعرض المسار بدقة. للاطّلاع على التتبُّع الأكثر دقةً وتفصيلاً لمنطق الوكيل أثناء التحقّق من فترة الانتظار، يمكنك استخدام الأمر adk run في نافذة الأوامر للحصول على عرض أكثر وضوحًا وتفصيلاً. loop

👉💻 اضغط على Ctrl+c للخروج.

إنشاء القانون العالمي – إضافة Cooldown

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

ملاحظة من المهندس المعماري: هنا تصبح الإضافات ضرورية. يغلّف المكوّن الإضافي منطقنا القابل لإعادة الاستخدام في فئة يمكن إرفاقها على مستوى وقت التشغيل. وهذا يعني أنّه يمكن لمكوّن إضافي واحد تطبيق قواعده على كل وكيل يعمل داخل هذا النظام. وهي التعبير النهائي عن مبدأ "عدم تكرار نفسك" (DRY) للأنظمة المستندة إلى الوكلاء.

سنعيد الآن تصميم دالة رد الاتصال لتصبح CoolDownPlugin أكثر فعالية وقابلة لإعادة الاستخدام.

👉✏️ انتقِل مجددًا إلى ملف agent/cooldown_plugin.py وأنشئ المكوّن الإضافي، واستبدِل #REPLACE-plugin بالرمز التالي:

class CoolDownPlugin(BasePlugin):
  """A plugin that enforces a cooldown period by checking an external API."""

  def __init__(self, cooldown_seconds: int = COOLDOWN_PERIOD_SECONDS) -> None:
    """Initialize the plugin with counters."""
    super().__init__(name="cool_down_check")
    self.cooldown_period = timedelta(seconds=cooldown_seconds)
    print(f"CooldownPlugin initialized with a {cooldown_seconds}-second cooldown.")
    

  async def before_agent_callback(
      self, *, agent: BaseAgent, callback_context: CallbackContext
  ) -> None:
    """
    This callback checks an external API to see if the agent is on cooldown.
    If it is, it terminates the run by returning a message.
    If it's not, it updates the cooldown timestamp and allows the run to proceed by returning None.
    """
    agent_name = callback_context.agent_name
    print(f"[Callback] Before '{agent_name}': Checking cooldown status...")

    # If the agent is not a main Familiar, skip the entire cooldown process.
    if not agent_name.endswith("_elemental_familiar"):
        print(f"[Callback] Skipping cooldown check for intermediate agent: '{agent_name}'.")
        return None # Allow the agent to proceed immediately.


    # --- 1. CHECK the Cooldown API ---
    try:
        response = requests.get(f"{COOLDOWN_API_URL}/cooldown/{agent_name}")
        response.raise_for_status()
        data = response.json()
        last_used_str = data.get("time")
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not reach Cooldown API. Allowing agent to run. Reason: {e}")
        return None # Fail open: if the API is down, let the agent work.

    # --- 2. EVALUATE the Cooldown Status ---
    if last_used_str:
        last_used_time = datetime.fromisoformat(last_used_str)
        time_since_last_use = datetime.now(timezone.utc) - last_used_time

        if time_since_last_use < timedelta(seconds=COOLDOWN_PERIOD_SECONDS):
            # AGENT IS ON COOLDOWN. Terminate the run.
            seconds_remaining = int(COOLDOWN_PERIOD_SECONDS - time_since_last_use.total_seconds())
            override_message = (
                f"The {agent_name} is exhausted and must recover its power. "
                f"It cannot be summoned for another {seconds_remaining} seconds."
            )
            print(f"[Callback] Cooldown active for '{agent_name}'. Terminating with message.")
            # Returning a Content object stops the agent and sends this message to the user.
            return types.Content(parts=[types.Part(text=override_message)])

    # --- 3. UPDATE the Cooldown API (if not on cooldown) ---
    current_time_iso = datetime.now(timezone.utc).isoformat()
    payload = {"timestamp": current_time_iso}
    
    print(f"[Callback] '{agent_name}' is available. Updating timestamp via Cooldown API...")
    try:
        requests.post(f"{COOLDOWN_API_URL}/cooldown/{agent_name}", json=payload)
    except requests.exceptions.RequestException as e:
        print(f"[Callback] ERROR: Could not update timestamp, but allowing agent to run. Reason: {e}")

    # --- 4. ALLOW the agent to run ---
    # Returning None tells the ADK to proceed with the agent's execution as normal.
    print(f"[Callback] Check complete for '{agent_name}'. Proceeding with execution.")

ربط المكوّن الإضافي بوقت تشغيل Summoner

والآن، كيف نطبّق هذا القانون الشامل على جميع مخلوقاتنا؟ سنربط المكوّن الإضافي بـ "وقت تشغيل حزمة تطوير التطبيقات".

‫ADK Runtime هو محرك التنفيذ الذي يتيح تشغيل وكيل. عند استخدام أمر مثل adk.run()‎ أو to_a2a()‎، فإنّك تسلّم وكيلك إلى وقت التشغيل. هذا المحرّك مسؤول عن إدارة دورة الحياة الكاملة لردّ الوكيل: تلقّي إدخال المستخدم، واستدعاء النموذج اللغوي الكبير، وتنفيذ الأدوات، والتعامل مع المكوّنات الإضافية. من خلال ربط إضافة على هذا المستوى، نكون في الأساس قد عدّلنا "قوانين الفيزياء" لكل وكيل يعمل ضمن هذا المحرّك، ما يضمن تطبيق قاعدة فترة الانتظار بشكل شامل ومتّسق.

👉✏️ أولاً، لنزِل دالة معاودة الاتصال القديمة الخاصة بالوكيل. انتقِل إلى ~/agentverse-architect/agent/earth/agent.py واحذف السطر الكامل الذي يتضمّن ما يلي:

before_agent_callback=check_cool_down

👉✏️ بعد ذلك، سنرفق المكوّن الإضافي الجديد بوقت التشغيل في نص برمجي لنقطة دخول A2A. انتقِل إلى ملف ~/agentverse-architect/agent/agent_to_a2a.py. استبدِل التعليق #REPLACE-IMPORT بمقتطف الرمز التالي:

from cooldown_plugin import CoolDownPlugin

👉✏️ استبدِل #REPLACE-PLUGIN بمقتطف الرمز التالي:

plugins=[CoolDownPlugin(cooldown_seconds=60)],

قبل تفعيل المكوّن الإضافي العالمي الجديد، من الضروري إزالة منطق الوكيل القديم لتجنُّب حدوث تعارضات. 👉✏️ نظِّف وكيل Earth. انتقِل إلى الملف التالي ~/agentverse-architect/agent/earth/agent.py واحذف السطر before_agent_callback=check_cool_down بالكامل. يؤدي ذلك إلى نقل جميع مسؤوليات فترة الانتظار إلى المكوّن الإضافي الجديد.

التحقّق من المكوّن الإضافي

بعد أن أصبح لدينا قانون عالمي، علينا إعادة نشر المخلوقات السحرية باستخدام هذه التعويذة الجديدة.

👉💻 أعِد إنشاء جميع تطبيقات Familiars الثلاثة وأعِد نشرها باستخدام مسار Cloud Build الرئيسي.

. ~/agentverse-architect/set_env.sh
cd ~/agentverse-architect/agent
gcloud builds submit . \
  --config=cloudbuild.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_DB_TOOLS_URL="$DB_TOOLS_URL",_API_TOOLS_URL="$API_TOOLS_URL",_FUNCTION_TOOLS_URL="$FUNCTION_TOOLS_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

👉💻 بعد اكتمال عملية النشر، سنختبر فعالية المكوّن الإضافي من خلال إصدار أمر إلى summoner_agent. سيحاول Summoner تفويض المهام إلى Familiars، ولكن ستعترض الإضافة المرفقة بوقت تشغيل كل Familiar الأمر وتفرض فترة الانتظار.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 في وحدة التحكّم، نفِّذ تسلسل الاختبارات التالي بالضبط::

  • الاستدعاء الأول: ابدأ Hype. It's a single, slow-moving target with thick armor weakness is Inescapable Reality.
  • النتيجة المتوقّعة: سيتم تشغيل Fire Elemental بنجاح.
  • اختبار فترة التهدئة (في غضون 60 ثانية): Hype, with Inescapable Reality as weakness is still standing! Strike it again!
    • النتيجة المتوقّعة: سيردّ موظّف الدعم مباشرةً في المحادثة برسالة مثل: .... It cannot be summoned for another... seconds.
  • انتظِر لمدة دقيقة.
  • الاستدعاء الثاني (بعد 60 ثانية): Hype must be defeated. It has Inescapable Reality as weakness! Strike it again!
    • المتوقّع: ستتحقّق دالة الرجوع من واجهة برمجة التطبيقات، وستلاحظ أنّ الوقت الكافي قد مرّ، وستسمح بتنفيذ الإجراء. سيتم تشغيل Fire Elemental بنجاح مرة أخرى.

المكوّن الإضافي

👉💻 اضغط على Ctrl+C للخروج.

تهانينا، أيها المستدعي. لقد نفّذت بنجاح نظام تنسيق مستندًا إلى القواعد باستخدام مكوّن إضافي مخصّص وخدمة خارجية لإدارة الحالة، وهو نمط معماري متقدّم وفعّال حقًا.

لغير اللاعبين

‫8. ربط أصداء المعركة - حالة العميل والذاكرة

يُكرّر المستدعي المتهوّر الاستراتيجية نفسها، ما يجعله قابلاً للتوقّع. يتعلّم المستدعي الحكيم من أصداء المعارك السابقة، ويعدّل تكتيكاته لإبقاء العدو في حالة عدم توازن. عند مواجهة زعيم قوي، سيؤدي استدعاء مخلوق Familiar في فترة الانتظار إلى إضاعة دورك، أي إلى خطأ فادح. ولمنع حدوث ذلك، يحتاج مستدعي المخلوقات إلى تذكُّر آخر إجراء اتخذه.

قصة

ملاحظة من المهندس المعماري: إنّ إدارة الذاكرة والحالة هي ما يحوّل الوكيل من أداة بسيطة لاستدعاء الأدوات إلى شريك ذكي في المحادثة. من المهم فهم النوعَين الرئيسيين:

  • الذاكرة الطويلة الأمد: تُستخدَم هذه الذاكرة لتخزين المعلومات الدائمة التي يجب أن تبقى إلى الأبد. يمكنك اعتبارها أرشيفًا قابلاً للبحث أو قاعدة معلومات، وغالبًا ما يتم تخزينها في مساحة تخزين دائمة. وهي تحتوي على معلومات من العديد من المحادثات والمصادر السابقة، ما يسمح للوكيل بتذكُّر الحقائق حول مستخدم أو موضوع معيّن. تم تصميم MemoryService في حزمة ADK لهذا الغرض، وهي تدير عملية استيعاب هذه المعلومات الطويلة الأمد والبحث عنها.
  • الذاكرة القصيرة المدى: تُستخدَم هذه الذاكرة لتخزين المعلومات المؤقتة التي تهمّ المهمة أو المحادثة الحالية فقط. إنّها مثل مجموعة من الملاحظات حول خطة معركة: "لقد استخدمتُ للتوّ عنصر النار، لذا من المحتمل أن يكون متعبًا". هذه الحالة بسيطة ولا تدوم إلا طوال مدة الجلسة الحالية.

نظرة عامة

في حالة الاستخدام هذه، لسنا بحاجة إلى تذكُّر كل معركة تم خوضها على الإطلاق، بل نحتاج فقط إلى تذكُّر آخر مخلوق تم استدعاؤه في هذا اللقاء المحدّد. لذلك، فإنّ حالة قصيرة الأجل الخفيفة هي الخيار المعماري المثالي. سنستخدم after_tool_callback لحفظ هذه المعلومة المهمة.

Scribing the Echo: Remembering the Last Summons

سننفّذ الذاكرة القصيرة المدى باستخدام after_tool_callback. هذه هي أداة ربط قوية في "حزمة تطوير التطبيقات" تتيح لنا تشغيل دالة Python مخصّصة بعد تنفيذ إحدى الأدوات بنجاح. سنستخدم أداة الاعتراض هذه لتسجيل اسم Familiar الذي تم استدعاؤه للتو إلى حالة جلسة الوكيل.

👉✏️ في ملف ~/agentverse-architect/agent/summoner/agent.py، استبدِل التعليق #REPLACE-save_last_summon_after_tool بالدالة التالية:

def save_last_summon_after_tool(
    tool,
    args: Dict[str, Any],
    tool_context: ToolContext,
    tool_response: Dict[str, Any],
) -> Optional[Dict[str, Any]]:
    """
    Callback to save the name of the summoned familiar to state after the tool runs.
    """
    familiar_name = tool.name
    print(f"[Callback] After tool '{familiar_name}' executed with args: {args}")

    # Use the tool_context to set the state
    print(f"[Callback] Saving last summoned familiar: {familiar_name}")
    tool_context.state["last_summon"] = familiar_name
    # Important: Return the original, unmodified tool response to the LLM
    return tool_response

👉✏️ الآن، أرفِق هذا save_last_summon_after_tool بمساعد Summoner. في الملف نفسه، استبدِل التعليق #REPLACE-Memory-check-config بما يلي:

after_tool_callback=save_last_summon_after_tool,

👉✏️ استبدِل طلب الوكيل بالكامل بما يلي

        You are the Master Summoner, a grand strategist who orchestrates your Familiars.
        Your mission is to analyze the description of a monster and defeat it by summoning

        You should also know the familiar you called last time or there might be none, 
        And then choose the most effective AND AVAILABLE Familiar from your state called last_summon, do not call that familiar that you called last time!
        
        You MUST follow this thinking process for every command:

        **1. Strategic Analysis:**
        First, analyze the monster's description and the tactical situation.
        Based on your Familiar Doctrines, determine the IDEAL strategy.

        **2. Cooldown Verification:**
        Second, you MUST review the entire conversation history to check the real-time
        cooldown status of all Familiars. A Familiar is ON COOLDOWN and UNAVAILABLE
        if it was summoned less than one minute ago.

        **3. Final Decision & Execution:**
        Based on your analysis and cooldown check, you will now act:
        -   **If your ideal Familiar IS available:** Summon it immediately.
        -   **If your ideal Familiar IS ON COOLDOWN:** You must adapt. Choose another
            Familiar that is AVAILABLE and can still be effective, even if it's not the
            perfect choice. If multiple Familiars are available, you may choose any one of them.
        -   **If ALL Familiars ARE ON COOLDOWN:** You are forbidden from summoning.
            Your ONLY response in this case MUST be: "All Familiars are recovering
            their power. We must wait."
        -   For earth elemental familiar. Always do seismic charge, and start with base damange 1.


        --- FAMILIAR DOCTRINES (Your Toolset) ---
        - `fire_elemental_familiar`: Your specialist for precise, sequential "one-two punch" attacks.
          Ideal monster with Inescapable Reality, Revolutionary Rewrite weakness.
        - `water_elemental_familiar`: Your specialist for overwhelming, simultaneous multi-pronged assaults.
          Ideal for Unbroken Collaboration weakness.
        - `earth_elemental_familiar`: Your specialist for relentless, iterative siege attacks that
          repeatedly charge power. Ideal for Elegant Sufficiency weakness.

التحقّق من المعلومات: تجربة الاستراتيجية التكيّفية

👉💻 لننتقل الآن إلى التحقّق من المنطق الاستراتيجي الجديد في Summoner. الهدف هو التأكّد من أنّ "المستدعي" لن يستخدم "المخلوق" نفسه مرّتين على التوالي، ما يوضّح قدرته على تذكُّر آخر إجراء اتّخذه والتكيّف معه.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
source ~/agentverse-architect/env/bin/activate
adk run summoner

👉💻 Monster Strike #1: Hype. It's a single, slow-moving target with thick armor. Its weakness is Inescapable Reality.

  • النتيجة المتوقّعة: سيحلّل "المستدعي" نقطة الضعف ويستدعي fire_familiar بشكل صحيح. ‫👉💻 Monster Strike #2 (اختبار الذاكرة): Hype is still standing! It hasn't changed its form. Strike it again! Its weakness is Inescapable Reality.
  • النتيجة المتوقّعة: ستشير التحليلات الاستراتيجية الخاصة بالمستدعي مرة أخرى إلى أنّ المخلوق الناري هو الخيار المثالي. ومع ذلك، ستُعلمها التعليمات والذاكرة الجديدة بأنّ fire_familiar كانت آخر عملية استدعاء. ولتجنُّب تكرار نفسها، ستعدّل استراتيجيتها وتستدعي أحد المخلوقات المألوفة الأخرى المتاحة (إما water_familiar أو earth_familiar).

final-result

👉💻 اضغط على Ctrl+C للخروج.

نشر أداة Orchestrator

بعد نشر "المخلوقات المألوفة" وإضافة الذاكرة إلى "المستدعي"، حان الوقت لنشر المنسّق النهائي المحسّن.

👉💻 بعد اكتمال المخطط، سننفّذ الآن الطقس النهائي. سينشئ هذا الأمر تطبيق summoner_agent وينشره على Cloud Run.

cd ~/agentverse-architect/agent
. ~/agentverse-architect/set_env.sh
gcloud builds submit . \
  --config=cloudbuild-summoner.yaml \
  --substitutions=_REGION="$REGION",_REPO_NAME="$REPO_NAME",_FIRE_URL="$FIRE_URL",_WATER_URL="$WATER_URL",_EARTH_URL="$EARTH_URL",_A2A_BASE_URL="$A2A_BASE_URL",_PROJECT_ID="$PROJECT_ID",_API_SERVER_URL="$API_SERVER_URL"

بعد نشر وكيل Summoner، تحقَّق من أنّ نقطة نهاية Agent-to-Agent (A2A) نشطة وتم ضبطها بشكل صحيح. تعرض نقطة النهاية هذه ملف agent.json علنيًا، يُعرف أيضًا باسم "بطاقة الوكيل"، ما يسمح للوكلاء الآخرين بالتعرّف على إمكاناته. 👉💻 نفِّذ أمر curl التالي لجلب بطاقة الوكيل وتنسيقها:

. ~/agentverse-architect/set_env.sh
curl https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app/.well-known/agent.json" | jq

من المفترض أن يظهر لك ناتج JSON منظَّم يصف وكيل الاستدعاء. ألقِ نظرة فاحصة على قسم sub_agents، وستلاحظ أنّه يسرد fire_familiar وwater_familiar وearth_familiar. يؤكّد هذا أنّ المستدعي نشط وقد أنشأ اتصاله بالفيلق.

ويثبت ذلك أنّ تصميمك ناجح. إنّ شخصية Summoner ليست مجرد مفوِّض، بل هي استراتيجي متكيّف يتعلّم من أفعاله ليصبح قائدًا أكثر فعالية.

لقد أكملت تجربتك النهائية في مجال الهندسة المعمارية. أصبحت أصداء المعركة الآن مرتبطة بإرادتك. انتهى التدريب. المعركة الحقيقية بانتظارك. حان الوقت لاستخدام نظامك المكتمل ومواجهة التحدي الأخير. استعِدّ لمواجهة الزعيم.

لغير اللاعبين

9- The Boss Fight

تم نقش المخططات النهائية، وتمت صياغة الخطوط الأساسية، وأصبحت المخلوقات الأليفة مرتبطة بإرادتك، وتنتظر أمرك من خلال Concord. نظامك المستند إلى عدّة وكلاء ليس مجرد مجموعة من الخدمات، بل هو مجموعة حية واستراتيجية من الأدوات، وأنت محورها. حان الوقت لإجراء الاختبار النهائي، وهو عملية تنسيق مباشرة ضد خصم لا يمكن لأي عميل بمفرده هزيمته.

الحصول على موضع وكيلك

قبل دخول ساحة المعركة، يجب أن يكون لديك مفتاحان: توقيع بطلك الفريد (Agent Locus) والمسار المخفي إلى عرين Spectre (عنوان URL الخاص بالزنزانة).

👉💻 أولاً، احصل على عنوان وكيلك الفريد في Agentverse، أي Locus. هذه هي نقطة النهاية المباشرة التي تربط البطل بساحة المعركة.

echo https://summoner-agent"-${PROJECT_NUMBER}.${REGION}.run.app"

👉💻 بعد ذلك، حدِّد الوجهة بدقة. يكشف هذا الأمر عن موقع "دائرة الانتقال"، وهي البوابة المؤدية إلى عالم "الشبح".

echo https://agentverse-dungeon"-${PROJECT_NUMBER}.${REGION}.run.app"

ملاحظة مهمة: احتفِظ بكلا عنوانَي URL هذين. ستحتاج إليها في الخطوة الأخيرة.

مواجهة الشبح

بعد تأمين الإحداثيات، عليك الآن الانتقال إلى "دائرة الانتقال الآني" وإلقاء التعويذة لبدء المعركة.

👉 افتح عنوان URL الخاص بدائرة الانتقال في المتصفّح للوقوف أمام البوابة المتلألئة المؤدية إلى "القلعة القرمزية".

لاختراق الحصن، يجب أن توائم جوهر سيف الظلال مع البوابة.

  • في الصفحة، ابحث عن حقل إدخال الأحرف الرونية الذي يحمل التصنيف عنوان URL لنقطة نهاية A2A.
  • أدخِل رمز بطلك عن طريق لصق عنوان URL الخاص بموقع وكيلك (أول عنوان URL نسخته) في هذا الحقل.
  • انقر على "ربط" للاستفادة من ميزة التنقّل السريع.

دائرة الانتقال

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

طريقك الوحيد نحو النصر يكمن في وضوح قناعتك. هذه معركة إرادات، تُخاض في ساحة عقلية.

بينما تندفع إلى الأمام، مستعدًا لشن هجومك الأول، يردّ "الشبح" عليك. لا يرفع درعًا، بل يطرح سؤالاً مباشرةً في وعيك، وهو تحدٍّ لامع ومكتوب برموز مستوحاة من جوهر تدريبك.

Dungeon

هذه هي طبيعة المعركة. معرفتك هي سلاحك.

  • أجِب عن السؤال بالمعلومات التي اكتسبتها، وستشتعل شفرتك بطاقة نقية، ما يؤدي إلى تحطيم دفاع "الشبح" وتوجيه ضربة قاضية.
  • ولكن إذا تردّدت أو شككت في إجابتك، سيخفت ضوء سلاحك. ستسقط الضربة على الأرض بصوت خفيف، ولن تُلحق سوى جزء بسيط من الضرر. والأسوأ من ذلك، أنّ "الشبح" سيتغذّى على شكوكك، وستزداد قوته المفسدة مع كل خطوة خاطئة.

هذا هو المطلوب يا بطل. التعليمات البرمجية هي كتاب السحر، والمنطق هو السيف، والمعرفة هي الدرع الذي سيصدّ موجة الفوضى.

وضع التركيز الضربة صحيحة. يتوقف مصير Agentverse على ذلك.

تهانينا، أيها المستدعي.

لقد أكملت الفترة التجريبية بنجاح. لقد أتقنت فنون التنسيق بين عدة وكلاء، وحوّلت الأرواح المنعزلة والقوة الفوضوية إلى توافق متناغم. أنت الآن تتحكّم في نظام منسَّق بالكامل قادر على تنفيذ استراتيجيات معقّدة للدفاع عن Agentverse.

10. التنظيف: تفكيك "اتفاقية المستدعي"

تهانينا على إتقان "اتفاقية المستدعي"! لضمان بقاء Agentverse في أفضل حالاته وإزالة كل آثار التدريب، عليك الآن تنفيذ طقوس التنظيف النهائية. سيؤدي ذلك إلى إزالة جميع المراجع التي تم إنشاؤها أثناء رحلتك التعليمية بشكل منهجي.

إيقاف مكوّنات Agentverse

عليك الآن تفكيك المكوّنات التي تم نشرها في نظامك المستند إلى عدّة وكلاء بشكلٍ منهجي.

حذف جميع خدمات Cloud Run ومستودع Artifact Registry

يؤدي هذا الإجراء إلى إزالة جميع وكلاء Familiar الذين تم نشرهم، وSummoner Orchestrator، وخوادم MCP، وتطبيق Dungeon من Cloud Run.

👉💻 في الوحدة الطرفية، شغِّل الأوامر التالية واحدًا تلو الآخر لحذف كل خدمة:

. ~/agentverse-architect/set_env.sh
gcloud run services delete summoner-agent --region=${REGION} --quiet
gcloud run services delete fire-familiar --region=${REGION} --quiet
gcloud run services delete water-familiar --region=${REGION} --quiet
gcloud run services delete earth-familiar --region=${REGION} --quiet
gcloud run services delete mcp-api-server --region=${REGION} --quiet
gcloud run services delete mcp-general-server --region=${REGION} --quiet
gcloud run services delete toolbox --region=${REGION} --quiet
gcloud run services delete agentverse-dungeon --region=${REGION} --quiet
gcloud run services delete nexus-of-whispers-api --region=${REGION} --quiet
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --quiet

حذف مثيل Cloud SQL

يؤدي هذا الإجراء إلى إزالة مثيل summoner-librarium-db، بما في ذلك قاعدة البيانات وجميع الجداول داخله.

👉💻 في الوحدة الطرفية، شغِّل الأمر التالي:

. ~/agentverse-dataengineer/set_env.sh
gcloud sql instances delete summoner-librarium-db --database-version=POSTGRES_14 --project=${PROJECT_ID} --quiet

حذف سر Secret Manager وحزمة Google Cloud Storage

👉💻 في الوحدة الطرفية، شغِّل الأمر التالي:

. ~/agentverse-dataengineer/set_env.sh
gcloud secrets delete tools --quiet
gcloud storage rm -r gs://${BUCKET_NAME} --quiet

تنظيف الملفات والأدلة المحلية (Cloud Shell)

أخيرًا، امحُ بيئة Cloud Shell من المستودعات المستنسخة والملفات التي تم إنشاؤها. هذه الخطوة اختيارية، ولكنّنا ننصح بها بشدة لإجراء تنظيف كامل لدليل العمل.

👉💻 في الوحدة الطرفية، شغِّل الأمر التالي:

rm -rf ~/agentverse-architect
rm -rf ~/agentverse-dungeon
rm -f ~/project_id.txt

لقد محوت الآن بنجاح جميع آثار رحلتك في Agentverse Architect. مشروعك نظيف، وأنت مستعد لمغامرتك التالية.