דלגו לתוכן

סוגי שלבי פייפליין

לשלב בפייפליין יש שני צירים בלתי תלויים:

  • סוג (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 אין גוף.

גוף שאינו עושה דבר של צומת ה-trigger המחויב — מסתיים מיד כדי שהמנוע יתפצל אל המאזינים במורד הזרם. ללא תצורה.

שלב מעטפת בלי סוכן (bash -c). מחזיקי המקום {{key}} בסקריפט מוחלפים ממצב + מטען הטריגר בערכים שעברו escaping עבור המעטפת.

שדה תצורה תיאור
script פקודת מעטפת להרצה (נדרש)
outputKey מפתח מצב שמקבל את ה-stdout המקוצץ ביציאה 0

פועל כשה-cwd הוא <cc_root>/pipelines/<pipelineRunId>/ (משותף לכל שלבי ה-bash בהרצה) ועם GITHUB_TOKEN בסביבה. כמו כן כותב <stepId>_runDir למצב. יציאה שאינה אפס מכשילה את השלב עם זנב ה-stderr.

צומת כללי של הנחיה ושליחה: מרנדר את ההנחיה, שולח את הסוכן אל שיחה ומשהה עד שההרצה מסתיימת. המטען של submit_output מהסוכן נאסף אל המצב תחת outputKey.

שדה תצורה תיאור
agentId UUID של סוכן בתחום סביבת העבודה שישלח (נדרש)
prompt טקסט ההנחיה; תומך בהחלפת {{key}} (נדרש)
outputKey מפתח מצב לפלט הנאסף
outputSchema סכימת JSON שהפלט חייב לעמוד בה
label תווית אנושית המוצגת על הקנבס
extras.spaceId שיחה קיימת לעבוד בה (ברירת מחדל: שיחה מוסתרת)
extras.conversationTitle זרם בעל שם בתוך אותו מרחב (אופציונלי)
extras.mode נקרא בצומת שפותח את החדר (messaging.createSpace), ולא כאן. ברירת מחדל review.

גוף מנתב — קורא את 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>} — שלילה.
  • Switch (extras.switchKey) — {"switchKey": "pr_class", "cases": [...], "default": "standard"}; מנתב למקרה הראשון שערך המצב מכיל בלי תלות ברישיות, ואם אין — ל-default.
  • השוואה (מפתחות עליונים מדור קודם extras.left / extras.op / extras.right) — שקול לפרדיקט comparison, ונשמר לתבניות שנכתבו לפני העץ.

הקשתות היוצאות מהצומת נושאות routeKey שחייב להתאים למפתח המוחזר.

מפרסם את הממצאים המאוחדים כהערת סקירה בבקשת משיכה דרך לקוח ה-PR של GitHub.

מפתח מצב תיאור
repo_full_name owner/repo (נדרש)
pr_number מספר PR — int או מחרוזת מספרית (נדרש)
consolidated_findings גוף ההערה (נדרש)

מחזיר StepResult.terminal עם comment_review_id ו-commented_at במצב.

מפרסם הודעה למרחב הודעות דרך MessagingPort.

מפתח מצב תיאור
space_id מרחב היעד (נדרש)
content גוף ההודעה, נקרא כלשונו מהמצב (נדרש)

כותב posted_space_id ו-posted_at למצב.

שולח צוות שלם במקום סוכן יחיד, ואז משהה עד שההרצות של החברים מסתיימות.

שדה תצורה תיאור
teamId צוות בתחום סביבת העבודה שישלח (נדרש; בלעדי הדדית עם agentId)
prompt טקסט המטרה; תומך בהחלפת {{key}} (נדרש)
dispatchMode allParallel (ברירת מחדל — משימה אחת לכל חבר) או manager (לשלוח רק את המוביל כדי לתאם)
outputKey מפתח מצב לפלטי החברים הנאספים
outputSchema, label, extras.spaceId כמו ב-conversation.promptAgent

שער אישור. שולח את סוכן המאשר אל שיחה (במצב review) עם הנחיית השער וחוזה פלט {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; שני הכלים אינם קיימים באף חבילה או מרשם.

מסיר עצי עבודה מבודדים מיושנים; בוחר את המצב שלו ממטען הטריגר. מכבד את הדגל dryRun של ההרצה.

מפתח מצב תיאור
ticket_id משחרר את עצי העבודה של אותו כרטיס
repo_full_name + pr_number משחרר את עץ העבודה האפמרלי של עורך ה-PR
space_id מפרק את עצי העבודה והתיקייה של אותה שיחה
(אף אחד מהנ״ל) סורק את סביבת העבודה: תיקיות שנעלמו, מרחבים מתים, תיקיות שיחה מיותמות

outputKey (אופציונלי) מקבל מחרוזת סיכום.

מיפוי / התפצלות על פני אוסף במצב: מרנדר את ההנחיה פעם אחת לכל פריט, ואז שולח את הסוכן פעם אחת עם ההנחיות האלה משורשרות (--- כמפרידים) ומשהה עד שההרצה הזו מסתיימת. אוסף ריק מסתיים מיד עם רשימה ריקה. זה אינו שליחה מקבילה אחת לכל פריט.

שדה תצורה תיאור
agentId סוכן שישלח לכל פריט (נדרש)
prompt הנחיה לכל פריט; תומכת בהחלפת {{key}} (נדרש)
extras.iterableKey מפתח מצב שמחזיק את האוסף (נדרש)
extras.itemKey המפתח שאליו הפריט הנוכחי נקשר בהנחיה (ברירת מחדל item)
outputKey מפתח מצב לפלט הנאסף (שליחה אחת, לא רשימה)

מריץ תבנית פייפליין אחרת כתת־שלב מקונן (פייפליין המשנה רץ כהרצת בן עם parentPipelineRunId מוגדר). השלב מושהה עד שהבן מגיע למצב סופי, ואז מצבו הסופי של הבן ממוזג תחת outputKey.

שדה תצורה תיאור
extras.templateId תבנית הבן להרצה (נדרש; פייפליין אינו יכול לקרוא לעצמו)
inputKeys מפתחות מצב שמועתקים אל מטען הטריגר של הבן
outputKey מפתח מצב למצבו הסופי הממוזג של הבן

אינדוקס tree-sitter ברקע: סורק מאגר, מחלץ סמלים/קשתות ב-isolates של עובדים ומזרים אותם אל גרף הקוד של סביבת העבודה. מזרים התקדמות אל שורת הרצת השלב; תומך בהרצה יבשה. Tree-sitter והדקדוקים שלו הם רכיבי native נדרשים — dylib חסר פירושו שהשרת מעולם לא עלה, ודקדוק שנכשל להיפתר באמצע ההרצה מכשיל את השלב במקום לדלג עליו.

מפתח מצב תיאור
repo_id מאגר לאינדוקס (נדרש)
repo_local_path נתיב מקומי של הצ׳קאאוט (נדרש)

הפרדת דוברים במצב לא מקוון. קוראת את האודיו שנשמר של הפגישה, מקבצת אותו לדוברים (Person 1, Person 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 מחיל תוויות Person 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 השלב האחרון של תבנית סקירת ה-PR: ממיין את צומתי הסקירה המצטברים לקבוצות קונצנזוס ומחשב את ההכרעה לכל PR.
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) השלב נכשל עם הודעת שגיאה

התנהגות ניסיון חוזר לגוף צומת שנכשל (PipelineNodeConfig.retryPolicy; null מבטל ניסיונות חוזרים).

שדה סוג תיאור
maxAttempts int סך הניסיונות כולל הראשון (3 = ניסיון אחד + 2 ניסיונות חוזרים); חייב להיות ≥ 1
backoff String linear או exponential (ברירת מחדל)
initialDelayMs int השהיה לפני הניסיון החוזר הראשון, במילישניות; ההשהיות הבאות גדלות לפי backoff

תצורה לפי צומת, הנישאת בתוך הגדרת השלב (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 (תת־קבוצה) שערך הפלט חייב לעמוד בה
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'] — מדלג על הצומת כשלא מתקיים).