عُقد الإجراءات

تعرّف حزمة adk-action 14 نوعًا من عُقد الإجراءات المستخدمة في سير العمل القائم على الرسوم البيانية. يمثّل كل نوع من العُقد عملية منفصلة (استدعاء HTTP، تحويل البيانات، فرع شرطي، وما إلى ذلك) يمكن تركيبها في رسوم بيانية موجّهة عبر ActionNodeExecutor الخاص بـ adk-graph.

نظرة عامة

تُعدّ عُقد الإجراءات اللبنات الأساسية للرسوم البيانية المرئية والبرمجية لسير العمل. وهي توفّر:

  • عمليات محددة الأنواع — 14 نوعًا من العُقد تغطي أنماط سير العمل الشائعة
  • StandardProperties — إعدادات مشتركة لمعالجة الأخطاء، والتتبّع، وربط البيانات
  • استبدال المتغيرات — صيغة {{variable}} للقيم الديناميكية
  • التكامل مع الرسم البياني — تُنفَّذ بواسطة ActionNodeExecutor الخاص بـ adk-graph

التثبيت

[dependencies]
adk-action = "2.1.0"

# Or specific action features via umbrella crate
adk-rust = { version = "2.1.0", features = ["action"] }

أنواع العُقد (14)

العقدةالغرضالفئة
Triggerنقطة الدخول — تبدأ تنفيذ سير العملالتحكم
HTTPإجراء طلبات HTTP (GET، POST، PUT، DELETE، PATCH)الإدخال/الإخراج
Setتعيين قيم لمتغيرات سير العملبيانات
Transformتحويل البيانات باستخدام التعبيرات أو التعليمات البرمجيةبيانات
Switchالتفرع الشرطي استنادًا إلى التعبيراتتحكم
Loopالتكرار عبر المجموعات أو حتى تحقق شرطتحكم
Mergeدمج فروع متعددة معًاتحكم
Waitإيقاف التنفيذ مؤقتًا لمدة محددة أو حتى وقوع حدثتحكم
Codeتنفيذ تعليمات برمجية عشوائية (Rust؛ لم يتم تنفيذ JS/TS)حساب
Databaseالاستعلام عن قواعد البيانات — لم يتم التنفيذإدخال/إخراج
Emailإرسال رسائل البريد الإلكتروني عبر SMTP — غير مُنفَّذالإدخال/الإخراج
Notificationإرسال الإشعارات (Slack، webhook، push)الإدخال/الإخراج
RSSقراءة وتحليل موجزات RSS/Atomالإدخال/الإخراج
Fileقراءة الملفات وكتابتها وتحويلهاالإدخال/الإخراج

يتم التحقق من التوفر عند بناء الرسم البياني

تقبل بعض أنواع العقد إعدادًا وتتحقق من صحته، حتى عندما لا تكون الواجهة الخلفية الخاصة بها موجودة.
ترفضها StateGraph::compile()، وليس في منتصف عملية التشغيل:

الإعدادالحالة
Database (أي نوع)مرفوض — لا يوجد برنامج تشغيل مدمج
Email (مراقبة أو إرسال)مرفوض — لم يتم تنفيذ IMAP وSMTP
Code مع language: javascript أو typescriptمرفوض — لا توجد بيئة تشغيل معزولة؛ استخدم rust
Http بدون ميزة action-httpمرفوض — فعّل الميزة

يُسمّي الرفض العقدة والسبب، لذا يفشل سير العمل الذي لا يمكن تشغيله أثناء تجميعه، بدلًا من فشله بعد أن تكون العقد السابقة قد أحدثت آثارًا جانبية بالفعل.

نفّذ Node::validate على عقدة مخصّصة للمشاركة في الفحص نفسه.

StandardProperties

تحمل كل عقدة إجراء StandardProperties — وهي تهيئة مشتركة تتحكم في سلوك التنفيذ:

use adk_action::{StandardProperties, ErrorHandling, RetryConfig};

let props = StandardProperties::builder()
    // Error handling
    .on_error(ErrorHandling::ContinueOnFail)
    .retry(RetryConfig {
        max_attempts: 3,
        wait_between_ms: 1000,
    })

    // Tracing
    .notes("Fetch user profile from API")

    // Callbacks
    .on_success("notify_complete")
    .on_failure("alert_team")

    // Execution
    .timeout_ms(30_000)
    .continue_on_fail(true)

    // Input/output mapping
    .input_mapping("{{trigger.body.user_id}}")
    .output_key("user_profile")

    .build();

StandardProperties الحقول

الحقلالنوعالوصف
on_errorErrorHandlingStop أو ContinueOnFail أو RetryThenFail
retryOption<RetryConfig>محاولات إعادة المحاولة والتأخير بينها
notesOption<String>وصف قابل للقراءة البشرية للتتبّع
on_successOption<String>عقدة رد الاتصال التي سيتم تنفيذها عند النجاح
on_failureOption<String>عقدة رد الاتصال التي سيتم تنفيذها عند الفشل
timeout_msOption<u64>الحد الأقصى لوقت التنفيذ
continue_on_failboolما إذا كانت العقد اللاحقة تُنفَّذ بعد الفشل
input_mappingOption<String>تعبير لتحويل بيانات الإدخال
output_keyOption<String>اسم المتغير لتخزين المخرجات

استيفاء المتغيرات

تدعم عُقد الإجراءات صيغة {{variable}} للإشارة إلى حالة سير العمل:

use adk_action::HttpNode;

let node = HttpNode::builder()
    .url("https://api.example.com/users/{{trigger.body.user_id}}")
    .method("GET")
    .headers(vec![
        ("Authorization".into(), "Bearer {{env.API_TOKEN}}".into()),
    ])
    .build();

مصادر المتغيرات

البادئةالمصدرالمثال
triggerحمولة عقدة المشغّل{{trigger.body.email}}
envمتغيرات البيئة{{env.DATABASE_URL}}
nodesمخرجات العقد السابقة{{nodes.fetch_user.json.name}}
workflowالمتغيرات على مستوى سير العمل{{workflow.run_id}}

يستخدم الوصول المتداخل تدوين النقاط: {{nodes.http_1.json.data[0].id}}

أمثلة على العُقد

عقدة HTTP

use adk_action::{HttpNode, HttpMethod};

let node = HttpNode::builder()
    .method(HttpMethod::Post)
    .url("https://api.example.com/orders")
    .headers(vec![
        ("Content-Type".into(), "application/json".into()),
    ])
    .body(r#"{"item": "{{trigger.body.item}}", "qty": {{trigger.body.quantity}}}"#)
    .properties(StandardProperties::builder()
        .timeout_ms(10_000)
        .on_error(ErrorHandling::RetryThenFail)
        .retry(RetryConfig { max_attempts: 3, wait_between_ms: 2000 })
        .output_key("order_response")
        .build())
    .build();

عقدة التبديل

use adk_action::{SwitchNode, SwitchCase};

let node = SwitchNode::builder()
    .cases(vec![
        SwitchCase {
            condition: "{{nodes.classify.json.category}} == 'urgent'".into(),
            output: "urgent_path".into(),
        },
        SwitchCase {
            condition: "{{nodes.classify.json.category}} == 'normal'".into(),
            output: "normal_path".into(),
        },
    ])
    .fallback("default_path")
    .build();

عقدة التكرار

use adk_action::{LoopNode, LoopMode};

let node = LoopNode::builder()
    .mode(LoopMode::ForEach {
        items: "{{nodes.fetch_users.json.users}}".into(),
        item_var: "current_user".into(),
    })
    .body_nodes(vec!["process_user", "save_result"])
    .properties(StandardProperties::builder()
        .notes("Process each user in the list")
        .build())
    .build();

عقدة التعيين

use adk_action::SetNode;

let node = SetNode::builder()
    .assignments(vec![
        ("status".into(), "processing".into()),
        ("started_at".into(), "{{workflow.timestamp}}".into()),
        ("user_email".into(), "{{trigger.body.email}}".into()),
    ])
    .build();

التكامل مع adk-graph

تُنفَّذ عُقد الإجراءات بواسطة ActionNodeExecutor الخاصة بـ adk-graph:

use adk_graph::{Graph, ActionNodeExecutor};
use adk_action::{TriggerNode, HttpNode, SetNode};

// Define nodes
let trigger = TriggerNode::webhook("order_received");
let fetch = HttpNode::get("https://api.example.com/inventory/{{trigger.body.sku}}");
let update = SetNode::new(vec![("available", "{{nodes.fetch.json.quantity}}")]);

// Build graph
let graph = Graph::builder()
    .node("trigger", trigger)
    .node("check_inventory", fetch)
    .node("update_status", update)
    .edge("trigger", "check_inventory")
    .edge("check_inventory", "update_status")
    .build()?;

// Execute
let executor = ActionNodeExecutor::new();
let result = executor.run(graph, initial_context).await?;

تعريف أنواع عُقد مخصّصة

طبّق سمة ActionNode:

use adk_action::{ActionNode, ActionContext, ActionResult, StandardProperties};
use async_trait::async_trait;

struct CustomNode {
    config: MyConfig,
    properties: StandardProperties,
}

#[async_trait]
impl ActionNode for CustomNode {
    fn node_type(&self) -> &str { "custom" }
    fn properties(&self) -> &StandardProperties { &self.properties }

    async fn execute(&self, ctx: &ActionContext) -> ActionResult {
        let input = ctx.resolve("{{trigger.body.data}}")?;
        // Custom logic...
        Ok(serde_json::json!({ "result": "processed" }))
    }
}

السابق: ← إعادة المحاولة والتأمل | التالي: الإضافات →

عُقد الإجراءات - وثائق ADK-Rust | ADK-Rust