في فصل الـ Input، تحقّقنا من أن query نص صالح وأن limit ضمن الحدود. هذه القيم ما زالت ضمن Input الخاص بالـ Tool داخل المكتبة. لكي تستفيد منها API، يجب تحديد أين تُرسل وبأي اسم.
هذا هو دور request.map. تخيّل أنك تكتب طلب curl يدويًا: قيمة داخل المسار، وأخرى بعد علامة الاستفهام، وثالثة في JSON body. Mapping يحدد هذه الوجهات دون أن يترك تركيب الطلب للـ AI Model.
اقرأ أبسط سطر ربط من اليمين إلى اليسار
في Tool البحث كتبنا:
# Inside request.map:
query:
q: $.query
$.query يقرأ الـ Input الذي اسمه query. وq هو الاسم الذي تستقبله API. أما كلمة query التي تعلو السطرين فهي نوع الوجهة في HTTP؛ تشابه الاسمين لا يعني أنهما يشيران إلى الشيء نفسه.
لهذا يمكنك تسمية الـ Input search_term، ثم كتابة q: $.search_term، ويبقى طلب API نفسه. لكنك ستحتاج إلى تحديث input_schema وinput.json لاستخدام الاسم الجديد.
المسار $ يبدأ من مصدر القيمة المحدد. في الصيغة المختصرة هنا، المصدر هو Input الـ Tool. عندما نستخدم source: session لاحقًا، يبدأ المسار من context الذي مرّره تطبيقك. لا توجد مساحة متغيرات مشتركة يبحث فيها Runtime عن أي اسم يجده.
انتقل إلى طلب فيه path وquery معًا
الآن تخيّل أن API لديك توفر المواعيد لخدمة محددة. الطلب المباشر الناجح هو:
GET /services/svc-color/slots?date=2026-10-01&limit=5
X-Locale: ar
الجزء svc-color من المسار، بينما date وlimit معاملات query. وX-Locale header. لن نضع القيم الثلاث في query لمجرد أنها كلها Input.
في المثال التالي، service_id هو ID لخدمة موجودة في الـ API لديك؛ لا تفترض أن المستخدم يعرفه. إذا احتجت إلى إيجاده من اسم الخدمة، أضف Dependency بعد فهم Mapping.
هذا تعريف Tool تضيفه كعنصر في قائمة tools. استبدل العنوان والحقول وفق متطلبات الـ Endpoint لديك:
- id: find-slots
tool:
description: Find available appointment slots for a service and date.
input_schema:
type: object
properties:
service_id: { type: string, minLength: 1 }
date: { type: string, format: date }
limit: { type: integer, minimum: 1, maximum: 20, default: 5 }
required: [service_id, date]
request:
method: GET
url: https://api.example.com/services/{service}/slots
map:
path:
service: $.service_id
query:
date: $.date
limit: $.limit
headers:
X-Locale:
source: constant
value: ar
عند تمرير { service_id: "svc-color", date: "2026-10-01" }، يضيف التحقق القيمة الافتراضية limit: 5. يستبدل Mapping {service}، ويضيف query parameters، ويكتب header. لا يختار الـ AI Model عنوان الخادم، ولا يبني URL بنفسه.
جرّب إرسال limit بالقيمة "5". يفشل التحقق؛ فلا يحوّل AGENTO النص إلى رقم تلقائيًا. وجرّب حذف service_id؛ سيطلب Runtime الـ Input الناقص قبل إرسال HTTP.
افهم وجهات Mapping الأربع
| الوجهة | متى تستخدمها؟ | أثرها أثناء التنفيذ |
|---|---|---|
request.map.path | أجزاء URL مثل ID الخدمة | تستبدل {placeholders} بقيم بسيطة بعد ترميزها. إذا غابت القيمة، يبقى الـ Placeholder دون قيمة ويتوقف التنفيذ. |
request.map.query | البحث والتاريخ والتصفية وتقسيم النتائج | تضيف Query Parameters إلى URL. إذا كانت القيمة مصفوفة، يتكرر اسم الـ Parameter لكل عنصر، مثل tag=a&tag=b. |
request.map.body | حقول JSON لطلبات POST وPUT وPATCH وDELETE | تبني كائن JSON من الحقول المربوطة. يرفض compiler وجود body مع GET أو HEAD. |
request.map.headers | بيانات غير سرية مثل اللغة | تحوّل القيم البسيطة إلى نصوص. بيانات الاعتماد وheaders المحجوزة مرفوضة؛ استخدم request.auth. |
مفاتيح body تمثل حقول المستوى الأول. لإرسال كائن متداخل، اربط الكائن المعرّف في الـ Schema كاملًا بحقل واحد؛ كتابة نقاط في اسم الوجهة لا تبني كائنًا متداخلًا.
# Fragment inside request.map of a confirmed write tool.
body:
customer: $.customer
channel:
source: constant
value: web
مع الـ Input { customer: { name: "Maya" } }، يصبح body هو {"customer":{"name":"Maya"},"channel":"web"}. عرّف شكل customer في tool.input_schema، واضبط Side Effects وConfirmation لأن العملية تكتب بيانات.
اختر مصدر القيمة عن قصد
المسار $.date اختصار لـ{ source: tool-input, path: $.date }. يبدأ المسار دائمًا من المصدر المختار، وليس من مساحة متغيرات عامة.
| المصدر | أين يبدأ المسار؟ | الاستخدام المناسب |
|---|---|---|
tool-input | arguments الـ Tool بعد التحقق وحسم الـ Dependencies | قيم المستخدم، والقيم التي ملأتها الـ Dependencies صراحةً. |
session | كائن context الذي يمرّره التطبيق المضيف | tenant أو اللغة أو سياق موثوق آخر. لا يتيح قراءة سجل الـ Session الداخلي أو بيانات الاعتماد. |
dependency | البيانات المحسومة للـ Dependency المباشرة المحددة | قيمة من استعلام معلن. بعد Selection، يكون المصدر هو العنصر المختار، وليس غلاف الـ Response الكامل. |
constant | القيمة المكتوبة في value | عملة أو قناة تطبيق ثابتة. كتابة SAR وحدها لا تمثل مصدرًا صالحًا. |
generated | UUID جديد | ربط الـ Request بالـ ID الخاص به لتتبّعه. يُولّد عند تجهيز الطلب، ولا يغني عن دعم idempotency في API. |
selection | حقائق العرض المعلنة للـ Selection | معاينة Confirmation فقط. يُمنع استخدامه في HTTP أو arguments الـ Dependencies. |
في source: session، كلمة session تشير إلى context الذي مرّره تطبيقك في الاستدعاء، لا إلى كل ما تحفظه المكتبة عن المحادثة. إذا مرّرت context: { tenantId: "t_1" }، فالمسار $.tenantId يقرأ t_1. لا يقرأ سجل الرسائل أو Session ID تلقائيًا.
أما source: constant فيرسل قيمة ثابتة من الإعداد. وsource: generated مع generator: uuid ينشئ UUID جديدًا؛ لا تستخدمه لاختراع ID لموعد أو عميل يجب أن يأتي من API.
المقاطع التالية داخل request.map.body لـ Tool تكتب بيانات لها سياسة Confirmation. لا تضف body إلى GET:
# Under request.map.body of a confirmed write tool:
tenant_id: { source: session, path: $.tenantId }
currency: { source: constant, value: SAR }
request_id: { source: generated, generator: uuid }
# Under request.map.body when availability is a declared dependency:
slot_token:
source: dependency
tool: availability
path: $.slot_token
مرّر السياق من خادم تطبيقك:
const result = await runtime.invoke({
sessionId: RANDOWM_SESSION_ID,
tool: "book",
arguments: { date: "2026-10-01" },
context: { tenantId: "t_1" },
auth: { token: USER_ACCESS_TOKEN },
});
المتغيرات هنا تأتي من تطبيقك بعد التحقق من هوية المستخدم. لا يتم نسخ tenant ID من كلام المستخدم. مكان بيانات الاعتماد هو auth، وليس Schema الـ Tool أو ربط context.
المسارات تقرأ الخصائص، ولا تنفّذ تعبيرات
تدعم المسارات $ و$.id و$.customer.address.city، وكذلك أجزاء الخصائص الرقمية عندما يسمح المصدر بها. لا تدعم $.items[*] أو $.items[0] أو filters أو تركيب النصوص أو استدعاء الدوال أو تعبيرات JavaScript.
يفحص compiler أيضًا وجود مسار tool-input داخل Schema المعلنة. قد يكون المسار صحيح الصياغة، لكنه يُرفض لأنه يقرأ خاصية لم تعرّفها. المسارات المتعلقة بـprototype محظورة.
استخدم depends_on.select للـ Selection من قائمة، بدل افتراض أن عنصرًا في موضع معيّن هو المطلوب.
غياب القيمة يختلف عن كونها فارغة
إذا غابت قيمة اختيارية من tool-input، يُحذف حقلها من الطلب. أما غياب قيمة من session أو Dependency فينتج INPUT_MAPPING_MISSING؛ لا يخترع الـ Runtime قيمة بديلة للـ Tenant أو الـ ID. القيمة null ليست غيابًا؛ يمكن إرسالها داخل JSON body، لكنها غير صالحة في URL أو header.
يجب أن تكون قيم path وheaders بسيطة. لا تقبل path الشرطات المائلة أو المحارف التحكّمية أو المقطعين . و... ولا تقبل headers فواصل الأسطر. يجب أن تحتوي مصفوفات query على قيم بسيطة فقط.
ميّز بين أنواع Mapping الثلاثة
# Fragment inside a dependency on services:
arguments:
q: $.service_query
map:
$.service_id: $.id
هذا مقطع مستقل داخل request للـ Tool الأم، وليس استمرارًا لمقطع الـ Dependency السابق:
map:
body:
service: $.service_id
- يمرّر
argumentsقيمةservice_queryمن الـ Tool الأم إلى الـ Inputqفي Tool البحث. - ينسخ
mapالخاص بالـ Dependency قيمةidمن نتيجتها إلىservice_idفي الـ Tool الأم. الطرف الأيسر هنا مسار وجهة. - يرسل
request.map.bodyالقيمة المحسومة باسمserviceإلى API. الطرف الأيسر هنا اسم حقل.
هذا الفرق أساس فهم الـ Dependencies والـ Selection.
اختبر حدود Mapping
قارن الطلب الذي يصل إلى الـ API في Staging بالـ Request المباشر الذي تعرف أنه يعمل. افحص URL وmethod وأسماء الحقول، دون تسجيل بيانات الاعتماد. يمكنك بعد ذلك استخدام Mock في الاختبارات الآلية لتثبيت هذا السلوك. اختبر غياب حقل اختياري، وغياب context مطلوب، ونوع بيانات غير صالح، وترميز أجزاء URL. يوفّر مثال الحجز المتكامل تجربة قابلة للتشغيل وتسلسل النتائج المتوقع.