الـ Side Effect هي عملية تغيّر بيانات العمل، مثل إنشاء حجز أو تعديل ملف أو خصم مبلغ من حساب أو حذف عنصر. في البحث كان إرسال الطلب يعيد معلومات فقط؛ أما هنا فقد تنشأ نتيجة فعلية لا يريدها المستخدم إذا أُرسلت بالخطأ.
يحدد behavior.effect نوع العملية، وتحدد confirmation متى تنتظر الموافقة. اختيار الـ AI Model لـ Tool الحجز يعبّر عن فهمه للطلب، لكنه لا يستدعي confirm() نيابة عن تطبيقك. سنفصل تجهيز العملية عن تنفيذها.
اختر التصنيف الذي يصف العملية
behavior.effect | مثال | النتيجة الملزمة |
|---|---|---|
read-only | GET للتوافر أو HEAD للبيانات الوصفية | الافتراضي، ويتيح استخدامها كـ Dependency تلقائية. |
side-effect | POST للحجز أو PATCH للملف | يتطلب confirmation.required: true، ولا يصلح كـ Dependency تلقائية. |
destructive | DELETE للحجز أو إزالة لا يمكن التراجع عنها | يتطلب Confirmation وضوابط الكتابة نفسها، لكنه لا يضيف شاشة موافقة ثانية تلقائيًا. |
يرفض الـ Compiler الحالي تصنيف أي Method غير GET وHEAD على أنها read-only. حتى Endpoint تستخدم POST للبحث تحتاج إلى تصنيف Side Effect في هذا الإصدار. لا تستخدم read-only لتجاوز Confirmation.
ابدأ بعملية الحجز
هذا قسم behavior من إعداد الحجز الكامل:
behavior:
effect: side-effect
confirmation:
required: true
ttl_ms: 30000
preview:
date: $.date
time: { source: selection, path: $.time }
notes: $.notes
تخبر effect: side-effect المكتبة أن العملية تغيّر البيانات. وتفرض required: true التوقف قبل التنفيذ. أما ttl_ms: 30000 فتعطي المستخدم ثلاثين ثانية للمراجعة ما لم تنتهِ بيانات يعتمد عليها الطلب قبل ذلك. وتحدد preview المعلومات التي سيوافق عليها.
إذا لم تحدد behavior.effect المناسب، يرفض الـ Compiler عملية POST بالخطأ CONFIG_EFFECT_INVALID. وإذا حددت Side Effect دون فرض Confirmation، يعيد CONFIG_CONFIRMATION_INVALID. هذه أخطاء بدء تشغيل، وليست تلميحات للواجهة.
تغيّر إضافة هذا القسم التنفيذ فعليًا؛ بعد حسم الـ Input والـ Dependencies، يجهّز AGENTO طلب HTTP ويخزنه، ثم يعيد needs_confirmation وينتظر الموافقة. لم يُرسل الحجز بعد.
صمّم معاينة يستطيع المستخدم مراجعتها
المعاينة كائن بيانات تستطيع واجهتك عرضه، وليست نصًا يُنفّذ أو طلبًا جديدًا إلى API. في المثال، يقرأ date وnotes من Input الحجز، ويقرأ time من حقيقة العرض التي سمّيناها facts.time في فصل الـ Dependencies. هكذا يرى المستخدم التاريخ والوقت الفعليين بدل Token لا يفهمه.
يسار كل سطر في preview اسم الحقل الذي سيظهر في كائن المعاينة، ويمينه مصدر القيمة. تغيير اسم حقل المعاينة لا يغيّر body الحجز؛ ذلك ما زال تحت request.map.body.
القيم المحفوظة في Selection Facts للعرض فقط. استخدم ربط الـ Dependencies لتمرير Token الحقيقي إلى HTTP. يُمنع كشف بيانات اعتماد أو حقول private في المعاينة، كما تُمنع القيم generated. قراءة حقيقة اختيار غير معلنة تفشل compilation.
إذا حذفت preview، يعرض Runtime حقول الـ Input التي يراها الـ AI Model. قد يكون ذلك صالحًا تقنيًا لكنه ناقص المعنى؛ فالحقول التي تنتجها الـ Dependencies مخفية عن الـ AI Model، وقد لا يظهر وقت الموعد المختار. عرّف معاينة صريحة للعمليات المهمة.
التطبيق مسؤول عن إجراء الموافقة
تحتوي النتيجة على ID Confirmation وموعد انتهائه ومعاينته. اعرض المعاينة مع إجراء واضح للـ Confirmation. داخل server handler المرتبط به:
// Called only after the user approves the displayed action.
const next = await runtime.confirm({
sessionId: authenticatedConversationId,
confirmationId: displayedConfirmation.id,
auth: { token: userAccessToken },
});
استخدم الـ Session المصرّح بها والسياق نفسيهما. لا تقبل Session ID عشوائيًا من المتصفح. أعد الحالة التالية إلى الواجهة؛ فقد ترفض API العملية حتى بعد Confirmation.
إرسال «نعم» أو «yes» عبر chat() يعيد الـ Confirmation المعلّق ولا يرسل عملية الكتابة. بعد موافقة المستخدم، يستدعي تطبيقك confirm() ويمرّر قيمة confirmation.id في confirmationId. عند الرفض استخدم cancel()؛ إخفاء البطاقة وحده لا يلغي العملية.
افهم الانتهاء والإبطال
القيمة الافتراضية لـconfirmation.ttl_ms خمس دقائق، وتُكتب في الإعداد بالمللي ثانية: 300000. لكن الانتهاء الفعلي هو أقرب موعد بين هذه المدة وانتهاء الاختيارات أو الـ Dependencies. Confirmation مدته خمس دقائق لا يجعل الـ Token الخاص بالموعد صالحًا لخمس دقائق إذا انتهى بعد ثلاثين ثانية.
يربط Runtime Confirmation بالطلب المجهّز وسياق التنفيذ. تغيّر العملية أو السياق، أو انتهاء الـ Dependency، أو ID غير صحيح، أو إعادة الموافقة، يجعل الـ Confirmation غير صالح للمتابعة. لا تكرر ID نفسه؛ أعد تجهيز العملية المطلوبة واطلب مراجعة جديدة.
استهلاك Confirmation لا يضمن التسليم مرة واحدة
يحفظ AGENTO استهلاك Confirmation قبل إرسال HTTP، فلا يُفترض أن تنفّذ الموافقة نفسها العملية مرارًا. لكن قد تنتهي المهلة بعد قبول API للحجز، أو يتوقف worker بين الإرسال وتسجيل النجاح.
للعمليات المهمة، وفّر idempotency في backend وطريقة للاستعلام عن حالة العملية. عند ظهور TOOL_EXECUTION_UNCERTAIN، تحقق من حالة العملية لدى الـ API قبل محاولة إنشاء الحجز من جديد.
# request fragment, only when the API honors this header:
idempotency:
header: Idempotency-Key
source: generated
retry:
attempts: 3
يُضاف المفتاح إلى الطلب المجهّز، ويُعاد استخدامه في محاولات النقل التابعة له. أما invocation جديد بالكامل فيجهّز مفتاحًا جديدًا. هذا الخيار لا ينفّذ منع التكرار داخل خادمك. اقرأ سياسة HTTP.
حدّث الخيار غير المتاح ثم اطلب الموافقة من جديد
إذا أعادت API الحالة 409 أو 410 بسبب اختفاء الموعد، أضف:
# Merge into behavior on the parent write tool.
recovery:
refresh_dependency: availability
statuses: [409, 410]
يجب أن تكون الـ Dependency المحددة معلنة مباشرةً في الـ Tool. يحذف Runtime قيمها القديمة، ويعيد الاستعلام للقراءة فقط، ثم يعيد اختيارًا أو Confirmation جديدًا. لا يوافق على البديل تلقائيًا.
استخدم recovery عندما تعني هذه الحالات فعلًا أن بيانات الـ Dependency أصبحت قديمة. لا تفسّر 409 الناتجة عن قاعدة عمل أخرى تلقائيًا على أنها طلب لتغيير الموعد.
اختبر السياسة نفسها
شغّل مثال الحجز، ثم تحقق من هذه الحدود: لا POST قبل الموافقة، وPOST واحد بعدها، وعدم إرسال POST ثانٍ عند تكرار ID، ورفض Confirmation المنتهي، وطلب مراجعة جديدة بعد إعادة جلب الخيارات بعد تلقي الحالة 409. تثبت هذه الاختبارات السياسة أكثر من مجرد ظهور بطاقة Confirmation.