أنواع خطوات خط الأنابيب
لخطوة خط الأنابيب محوران مستقلان:
- النوع (
StepKind) — كيف يجدول المحرّك الخطوة بالنسبة إلى مشغّلاتها. - مفتاح الجسم (
BuiltInBodyKeys) — أي دالة مغلقة مسجّلة للجسم تنفّذ عمل الخطوة.
أنواع الخطوات
قسم بعنوان “أنواع الخطوات”معرّفة في packages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart.
| النوع | دلالات الجدولة |
|---|---|
trigger |
نقطة دخول إلزامية — واحدة بالضبط لكل قالب، وهي دائمًا العقدة الأولى. لا تؤدي عملًا بنفسها؛ ما يبدأ التشغيل (يدوي / حدث / جدولة) يُتتبَّع منفصلًا في صفوف PipelineTrigger. جسمها هو pipeline.trigger الذي لا يفعل شيئًا. |
listen |
تنطلق حين تكتمل كل الخطوات المصدر (في StepTrigger.sourceStepIds). |
join |
تنطلق حين تبلغ كل الخطوات في waitForStepIds حالة نهائية. |
router |
تفريع شرطي — يعيد الجسم StepResult.route(key)، فيُطلق الحافة التالية التي يطابق routeKey الخاص بها فقط؛ وتُعلَّم الفروع غير المختارة متخطاة. |
forEach |
تُجدول مثل listen (تنطلق حين تكتمل كل sourceStepIds). جسم flow.forEach المسجّل هو ما يكرّر؛ والمحرّك لا ينشئ خطوة ابنة لكل عنصر. |
terminal |
حارس للمجدول بلا جسم. يكتمل تشغيل خط الأنابيب حين تنتهي خطوة terminal. |
أجسام الخطوات
قسم بعنوان “أجسام الخطوات”دوال مغلقة مسجّلة للجسم، مفاتيحها ثوابت BuiltInBodyKeys (packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart). عددها 25، وكلها مدرجة أدناه. تُقرأ التهيئة من PipelineNodeConfig الخاص بالخطوة (انظر أدناه) ما لم يُذكر غير ذلك؛ وتُقرأ «مفاتيح الحالة» من حالة خط الأنابيب / حمولة المشغّل وقت التنفيذ.
خطوة ليس bodyKey الخاص بها مسجّلًا تُصدر تحذيرًا عند تحميل القالب ثم لا تُنفَّذ — ولا تُفشل التشغيل. خطوتا trigger وterminal مستثنيتان من هذا التحذير: المشغّل يظل يشغّل جسم pipeline.trigger الذي لا يفعل شيئًا؛ وخطوة terminal بلا جسم.
pipeline.trigger
قسم بعنوان “pipeline.trigger”جسم لا يفعل شيئًا لعقدة trigger الإلزامية — يكتمل فورًا حتى ينتشر المحرّك إلى المستمعات التالية. بلا تهيئة.
pipeline.bashScript
قسم بعنوان “pipeline.bashScript”خطوة صدفة بلا وكيل (bash -c). تُستبدَل مواضع {{key}} في السكربت من الحالة + حمولة المشغّل بقيم مُهرَّبة للصدفة.
| حقل الإعداد | الوصف |
|---|---|
script |
أمر الصدفة المطلوب تنفيذه (مطلوب) |
outputKey |
مفتاح الحالة الذي يستقبل stdout بعد قص المسافات عند الخروج 0 |
تعمل بدليل العمل <cc_root>/pipelines/<pipelineRunId>/ (مشترك بين كل خطوات bash في التشغيل) ومع GITHUB_TOKEN في البيئة. وتكتب أيضًا <stepId>_runDir في الحالة. الخروج بغير صفر يُفشل الخطوة بذيل stderr.
conversation.promptAgent
قسم بعنوان “conversation.promptAgent”عقدة عامة للموجّه والإرسال: تصيغ الموجّه، وترسل الوكيل إلى محادثة، وتُعلَّق حتى ينتهي التشغيل. تُستخلَص حمولة submit_output الخاصة بالوكيل في الحالة تحت outputKey.
| حقل الإعداد | الوصف |
|---|---|
agentId |
معرّف UUID لوكيل ضمن نطاق مساحة العمل يُرسَل (مطلوب) |
prompt |
نص التعليمات؛ يدعم استبدال {{key}} (مطلوب) |
outputKey |
مفتاح الحالة للمخرج المستخلَص |
outputSchema |
JSON Schema يجب أن يحققه المخرج |
label |
تسمية بشرية تُعرض على اللوحة |
extras.spaceId |
محادثة قائمة يُنجَز العمل فيها (الافتراضي: محادثة مخفية) |
extras.conversationTitle |
مجرى مسمّى داخل تلك المساحة (اختياري) |
extras.mode |
يُقرأ على العقدة التي تفتح الغرفة (messaging.createSpace)، لا هنا. الافتراضي review. |
pipeline.condition
قسم بعنوان “pipeline.condition”جسم موجّه — يقرأ config.extras، ويقيّم شرطًا، ويعيد StepResult.route(key). الشروط ليست تعبيرات JavaScript؛ وتُدعَم ثلاثة أشكال للتأليف، بترتيب الأولوية:
- شجرة محمولات (
extras.predicate) — شجرة منطقية توجّه"true"/"false". كل عقدة خريطة فيهاtype:{"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false}— تتحقق حين يوجد أي مسار من القائمة على القرص؛negateيعكسها؛recursiveيبحث أيضًا في الأدلة الفرعية (متخطيًا.gitوnode_modulesوbuildو.dart_tool). تُحَل المسارات النسبية مقابلstate[baseKey](الافتراضيrepo_local_path)، وإلا فدليل مساحة العمل الخاص بالتشغيل.{"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80}— المعاملاتequalsوnotEqualsوcontainsوexistsوnotExistsوgtوlt؛ تقرأ حالة خط الأنابيب، لا نظام الملفات.{"type": "and" | "or", "of": [<predicate>, ...]}— مجموعات منطقية.{"type": "not", "of": <predicate>}— نفي.
- تفريع (
extras.switchKey) —{"switchKey": "pr_class", "cases": [...], "default": "standard"}؛ يوجّه إلى أول حالة تحتويها قيمة الحالة بلا حساسية لحالة الأحرف، وإلاdefault. - مقارنة (المستوى الأعلى القديم
extras.left/extras.op/extras.right) — تعادل محمولcomparison، وتُبقى للقوالب التي أُلِّفت قبل الشجرة.
تحمل الحواف الخارجة من العقدة routeKey يجب أن يطابق المفتاح المعاد.
prReview.comment
قسم بعنوان “prReview.comment”ينشر النتائج المجمَّعة تعليق مراجعة على طلب السحب عبر عميل طلبات السحب في GitHub.
| مفتاح الحالة | الوصف |
|---|---|
repo_full_name |
owner/repo (مطلوب) |
pr_number |
رقم طلب السحب — عدد صحيح أو سلسلة رقمية (مطلوب) |
consolidated_findings |
متن التعليق (مطلوب) |
يعيد StepResult.terminal مع comment_review_id وcommented_at في الحالة.
messaging.postSpace
قسم بعنوان “messaging.postSpace”ينشر رسالة في مساحة مراسلة عبر MessagingPort.
| مفتاح الحالة | الوصف |
|---|---|
space_id |
المساحة المستهدفة (مطلوب) |
content |
متن الرسالة، يُقرأ حرفيًا من الحالة (مطلوب) |
يكتب posted_space_id وposted_at في الحالة.
team.dispatch
قسم بعنوان “team.dispatch”يرسل فريقًا كاملًا بدل وكيل واحد، ثم يُعلَّق حتى تنتهي تشغيلات الأعضاء.
| حقل الإعداد | الوصف |
|---|---|
teamId |
فريق ضمن نطاق مساحة العمل يُرسَل (مطلوب؛ لا يجتمع مع agentId) |
prompt |
نص الهدف؛ يدعم استبدال {{key}} (مطلوب) |
dispatchMode |
allParallel (الافتراضي — مهمة لكل عضو) أو manager (يُرسَل القائد فقط لينسّق) |
outputKey |
مفتاح الحالة لمخرجات الأعضاء المستخلَصة |
outputSchema, label, extras.spaceId |
كما في conversation.promptAgent |
human.gate
قسم بعنوان “human.gate”بوابة موافقة. ترسل وكيل الاعتماد إلى محادثة (وضع المراجعة) مع موجّه البوابة وعقد مخرج {decision, reason}، ثم تُعلَّق حتى يسلّم المعتمِد عبر submit_output.
| حقل الإعداد | الوصف |
|---|---|
agentId |
وكيل الاعتماد (مطلوب) |
prompt |
موجّه البوابة (اختياري؛ يُستخدَم افتراضي عند غيابه) |
outputKey |
مفتاح الحالة لحمولة {decision, reason} المستخلَصة |
outputSchema |
يفتَرض مخطط موافقة (decision: approved / rejected، وreason) |
label, extras.spaceId |
كما في conversation.promptAgent |
تُحسم البوابة عبر submit_output فقط. يسمّي BuiltInBodyKeys.humanGate ومكتبة العقد ونص موجّه أحد القوالب المضمّنة أداتي MCP approve_step وreject_step؛ ولا توجد أي من الأداتين في أي حزمة أو سجل.
repos.cleanup
قسم بعنوان “repos.cleanup”يزيل أشجار العمل المعزولة القديمة؛ ويختار نمطه من حمولة المشغّل. يلتزم بعلامة dryRun الخاصة بالتشغيل.
| مفتاح الحالة | الوصف |
|---|---|
ticket_id |
يزيل أشجار عمل تلك التذكرة |
repo_full_name + pr_number |
يزيل شجرة عمل محرّر طلب السحب المؤقتة |
space_id |
يفكّك أشجار عمل تلك المحادثة ومجلدها |
| (لا شيء مما سبق) | يمسح مساحة العمل: الأدلة المختفية، والمساحات الميتة، ومجلدات المحادثات اليتيمة |
يستقبل outputKey (اختياري) سلسلة ملخص.
flow.forEach
قسم بعنوان “flow.forEach”تعيين / انتشار على مجموعة في الحالة: يصيغ الموجّه مرة لكل عنصر، ثم يرسل الوكيل مرة واحدة بهذه الموجّهات مضمومة (فواصل ---) ويُعلَّق حتى ينتهي ذلك التشغيل. المجموعة الفارغة تكتمل فورًا بقائمة فارغة. ليس هذا إرسالًا متوازيًا لكل عنصر.
| حقل الإعداد | الوصف |
|---|---|
agentId |
الوكيل الذي يُرسَل لكل عنصر (مطلوب) |
prompt |
موجّه لكل عنصر؛ يدعم استبدال {{key}} (مطلوب) |
extras.iterableKey |
مفتاح الحالة الذي يحمل المجموعة (مطلوب) |
extras.itemKey |
المفتاح الذي يُربَط به العنصر الحالي في الموجّه (الافتراضي item) |
outputKey |
مفتاح الحالة للمخرج المستخلَص (إرسال واحد، لا قائمة) |
flow.callPipeline
قسم بعنوان “flow.callPipeline”يشغّل قالب خط أنابيب آخر كخطوة فرعية متداخلة (يعمل خط الأنابيب الفرعي تشغيلًا ابنًا مع ضبط parentPipelineRunId). تُعلَّق الخطوة حتى يبلغ الابن حالة نهائية، ثم تُدمَج الحالة النهائية للابن تحت outputKey.
| حقل الإعداد | الوصف |
|---|---|
extras.templateId |
القالب الابن المطلوب تشغيله (مطلوب؛ لا يستطيع خط الأنابيب استدعاء نفسه) |
inputKeys |
مفاتيح الحالة المنسوخة إلى حمولة مشغّل الابن |
outputKey |
مفتاح الحالة للحالة النهائية المدمجة للابن |
code.index
قسم بعنوان “code.index”فهرسة tree-sitter في الخلفية: يمشي مستودعًا، ويستخرج الرموز والحواف في عوازل العمال، ويُدخلها في مخطط الشفرة لمساحة العمل. يبث التقدّم في صف تشغيل الخطوة؛ ويدعم التشغيل التجريبي. tree-sitter وقواعده النحوية مكتبات أصلية مطلوبة — غياب dylib يعني أن الخادم لم يُقلِع، وقاعدة نحوية تفشل في الحل أثناء التشغيل تُفشل الخطوة بدل تخطيها.
| مفتاح الحالة | الوصف |
|---|---|
repo_id |
المستودع المطلوب فهرسته (مطلوب) |
repo_local_path |
المسار المحلي للنسخة (مطلوب) |
meeting.diarize
قسم بعنوان “meeting.diarize”تمييز المتحدثين بلا اتصال. يقرأ الصوت المحتفَظ به للاجتماع، ويجمّعه في متحدثين (الشخص 1، الشخص 2، …)، ويعيد تسمية مقاطع النص، ويعيد كتابة حالة transcript؛ ويُصدر أيضًا diarization_spans لخطوة meeting.updateTranscript المتوازية. يمرّر النص كما هو حين لا يُحتفَظ بصوت أو حين لا تكون النماذج مثبّتة.
| مفتاح الحالة | الوصف |
|---|---|
meeting_id |
الاجتماع المطلوب تمييز متحدثيه (مطلوب) |
meeting.saveNotes, meeting.addActionItems, meeting.addDecisions
قسم بعنوان “meeting.saveNotes, meeting.addActionItems, meeting.addDecisions”أجسام حفظ حتمية لملخص الاجتماع. يقرأ كل منها meeting_id وحمولة meeting_outcome المنظَّمة لخطوة الوكيل ({summary, enhancedNotes, actionItems[], decisions[]}) من الحالة ويكتب جزأه في جدوله — الملاحظات، أو بنود الإجراءات، أو القرارات. لا تُمسح الصفوف المحفوظة سابقًا في تشغيل متدهور.
أجسام مضمّنة أخرى
قسم بعنوان “أجسام مضمّنة أخرى”| مفتاح الجسم | الوصف |
|---|---|
meeting.identifySpeakers |
التعرّف على المتحدثين عبر الاجتماعات: يطابق المتحدثين المميَّزين مع ملفات الصوت المحفوظة ويطبّق المطابقات الواثقة تلقائيًا. لا يفعل شيئًا بلا ملفات صوت أو تضمينات. |
meeting.updateTranscript |
يطبّق تسميات الشخص N من diarization_spans ويدمج أجزاء كل نافذة في أدوار لكل متحدث، ثم يحفظ النص المنظَّف. لا يفعل شيئًا حين لا ينتج التمييز شيئًا. |
meeting.assemblePlayback |
يجمّع مسار التشغيل المختلط للاجتماع من ملفات WAV المحتفَظ بها لكل قناة. لا يفعل شيئًا حين لا يُحتفَظ بصوت. |
orchestration.markPhase |
في نهاية مخطط DAG للعمل، يكتب حراس فشل للتذاكر الفرعية التي بلا مخرج ويقلب التنسيق إلى synthesizing. |
orchestration.persistDeliverable |
يكتب مخرج التركيب في التذكرة الأم، ويكملها، وينشر المُخرَج، ويعلّم التنسيق completed. |
orchestration.awaitApproval |
بوابة موافقة جزئية: تكتمل فورًا حين يكون مفتاح عقدة الخطوة ضمن مجموعة التنسيق المعتمدة، وإلا تُعلَّق حتى تستأنفها موافقة لاحقة. هذا الجسم الوحيد الذي يضبط extras.awaitApproval، وهو ما يعفيه من مهلة الـ 24 ساعة للخطوة المعلّقة. |
messaging.createSpace |
يفتح المحادثة التي يعمل فيها بقية القالب، وتُنشَر تحت outputKey الخاص بالخطوة (القوالب المضمّنة تستخدم pipeline_space_id). قائمة repoIds الفارغة لا تسحب شيئًا؛ وextras['allRepos'] يسحب كل مستودع في مساحة العمل. extras['createConversation'] (مطفأ افتراضيًا) يفتح أيضًا مجرًى مسمّى. خطوة الوكيل تنضم إلى غرفة ولا تفتح واحدة أبدًا، فانتشار بلا هذه العقدة يفشل عند الإرسال — ووصلها مرة واحدة يعني أن الانتشار كله يشترك في نسخة واحدة بدل تجهيز نسخة لكل واحد. |
prReview.finalize |
الخطوة الأخيرة في قالب مراجعة طلب السحب: تفرز عقد المراجعة المتراكمة في مجموعات إجماع وتحسب الحكم لكل طلب سحب. |
skills.analyze |
يشغّل فحص سلسلة توريد المهارات على المهارات المثبّتة في مساحة العمل ويسجّل كل حكم. |
نتائج الخطوات
قسم بعنوان “نتائج الخطوات”يعيد جسم الخطوة StepResult (packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart). تقبل كل المصانع خريطة mutatedState اختيارية تُدمَج في حالة خط الأنابيب، باستثناء failed.
| المصنع | التوقيع | الوصف |
|---|---|---|
ok |
StepResult.ok({mutatedState}) |
اكتمال عادي؛ تُقيَّم المستمعات التالية |
route |
StepResult.route(nextRouterKey, {mutatedState}) |
اكتمال الموجّه؛ يختار الفرع التالي الذي يطابق routeKey الخاص به |
suspendUntilEvent |
StepResult.suspendUntilEvent(eventType, {mutatedState}) |
يتوقف حتى يُطلَق نوع معيّن من أحداث النطاق |
suspendUntilTasksComplete |
StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) |
يتوقف حتى تبلغ كل المهام المدرجة حالة نهائية |
terminal |
StepResult.terminal({mutatedState}) |
اكتمل تشغيل خط الأنابيب — لا خطوات بعده |
failed |
StepResult.failed(errorMessage) |
فشلت الخطوة برسالة خطأ |
StepRetryPolicy
قسم بعنوان “StepRetryPolicy”سلوك إعادة المحاولة لجسم عقدة فاشلة (PipelineNodeConfig.retryPolicy؛ القيمة null تعطّل الإعادة).
| الحقل | النوع | الوصف |
|---|---|---|
maxAttempts |
int |
مجموع المحاولات بما فيها الأولى (3 = محاولة + محاولتا إعادة)؛ ويجب أن يكون ≥ 1 |
backoff |
String |
linear أو exponential (الافتراضي) |
initialDelayMs |
int |
الإمهال قبل أول إعادة، بالمللي ثانية؛ وتنمو الإمهالات اللاحقة حسب backoff |
PipelineNodeConfig
قسم بعنوان “PipelineNodeConfig”تهيئة لكل عقدة تُحمَل داخل تعريف الخطوة (packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart). تشترك العقد المضمّنة والمخصّصة في هذا الشكل؛ ويقرأ كل جسم الحقول التي تهمه فقط.
| الحقل | النوع | الوصف |
|---|---|---|
prompt |
String? |
قالب موجّه مع استبدال {{key}} |
script |
String? |
متن سكربت Bash مع استبدال {{key}} |
agentId |
String? |
معرّف UUID لوكيل ضمن نطاق مساحة العمل يُرسَل |
inputKeys |
List<String> |
مفاتيح الحالة التي تستهلكها هذه العقدة مدخلًا |
repoIds |
List<String> |
المستودعات التي تسحبها عقدة messaging.createSpace (<repoId> أو <repoId>@<branch>). الفراغ = لا شيء؛ extras['allRepos'] = كل مستودع في مساحة العمل. يُتجاهَل على خطوات الوكيل. |
outputKey |
String? |
مفتاح الحالة الذي يُكتَب تحته مخرج هذه العقدة |
label |
String? |
تسمية بشرية تُعرض على اللوحة (الافتراضي معرّف الخطوة) |
outputSchema |
Map<String, dynamic>? |
JSON Schema (مجموعة جزئية) يجب أن تحققها قيمة المخرج |
reducer |
String? |
استراتيجية الدمج حين تكتب الفروع المتوازية outputKey نفسه: append أو mergeLists أو mergeMaps أو sum أو override (الافتراضي) |
retryPolicy |
StepRetryPolicy? |
سياسة إعادة المحاولة عند فشل الجسم؛ null = محاولة واحدة |
continueOnFail |
bool |
حين تكون true، لا يُفشل الفشل النهائي التشغيل؛ ويُودَع الخطأ تحت state['_stepErrors'][stepId] |
timeoutMs |
int? |
مهلة زمنية فعلية لجسم العقدة بالمللي ثانية؛ null = بلا مهلة |
teamId |
String? |
الفريق المطلوب إرساله (عقد team.dispatch)؛ لا يجتمع مع agentId |
dispatchMode |
String? |
وضع تنفيذ الفريق: allParallel أو manager |
extras |
Map<String, dynamic> |
تهيئة حرة خاصة بالجسم (مثل iterableKey وtemplateId وأشجار الشروط) |
الموصّلات المشتقة: spaceId (extras['spaceId'] — محادثة قائمة يُنجَز العمل فيها)، وcreatesConversation (extras['createConversation'])، وconversationTitle (extras['conversationTitle'])، وmodeName (extras['mode'] — chat / review / plan، تُقرأ على العقدة التي تفتح المساحة)، وrunWhen (extras['runWhen'] — تخطي العقدة حين لا يتحقق الشرط).