סוגי שלבי פייפליין
לשלב בפייפליין יש שני צירים בלתי תלויים:
- סוג (
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}} בסקריפט מוחלפים ממצב + מטען הטריגר בערכים שעברו escaping עבור המעטפת.
| שדה תצורה | תיאור |
|---|---|
script |
פקודת מעטפת להרצה (נדרש) |
outputKey |
מפתח מצב שמקבל את ה-stdout המקוצץ ביציאה 0 |
פועל כשה-cwd הוא <cc_root>/pipelines/<pipelineRunId>/ (משותף לכל שלבי ה-bash בהרצה) ועם GITHUB_TOKEN בסביבה. כמו כן כותב <stepId>_runDir למצב. יציאה שאינה אפס מכשילה את השלב עם זנב ה-stderr.
conversation.promptAgent
קטע בשם “conversation.promptAgent”צומת כללי של הנחיה ושליחה: מרנדר את ההנחיה, שולח את הסוכן אל שיחה ומשהה עד שההרצה מסתיימת. המטען של submit_output מהסוכן נאסף אל המצב תחת outputKey.
| שדה תצורה | תיאור |
|---|---|
agentId |
UUID של סוכן בתחום סביבת העבודה שישלח (נדרש) |
prompt |
טקסט ההנחיה; תומך בהחלפת {{key}} (נדרש) |
outputKey |
מפתח מצב לפלט הנאסף |
outputSchema |
סכימת JSON שהפלט חייב לעמוד בה |
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>}— שלילה.
- Switch (
extras.switchKey) —{"switchKey": "pr_class", "cases": [...], "default": "standard"}; מנתב למקרה הראשון שערך המצב מכיל בלי תלות ברישיות, ואם אין — ל-default. - השוואה (מפתחות עליונים מדור קודם
extras.left/extras.op/extras.right) — שקול לפרדיקטcomparison, ונשמר לתבניות שנכתבו לפני העץ.
הקשתות היוצאות מהצומת נושאות routeKey שחייב להתאים למפתח המוחזר.
prReview.comment
קטע בשם “prReview.comment”מפרסם את הממצאים המאוחדים כהערת סקירה בבקשת משיכה דרך לקוח ה-PR של GitHub.
| מפתח מצב | תיאור |
|---|---|
repo_full_name |
owner/repo (נדרש) |
pr_number |
מספר PR — int או מחרוזת מספרית (נדרש) |
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”שער אישור. שולח את סוכן המאשר אל שיחה (במצב 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; שני הכלים אינם קיימים באף חבילה או מרשם.
repos.cleanup
קטע בשם “repos.cleanup”מסיר עצי עבודה מבודדים מיושנים; בוחר את המצב שלו ממטען הטריגר. מכבד את הדגל dryRun של ההרצה.
| מפתח מצב | תיאור |
|---|---|
ticket_id |
משחרר את עצי העבודה של אותו כרטיס |
repo_full_name + pr_number |
משחרר את עץ העבודה האפמרלי של עורך ה-PR |
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 ברקע: סורק מאגר, מחלץ סמלים/קשתות ב-isolates של עובדים ומזרים אותם אל גרף הקוד של סביבת העבודה. מזרים התקדמות אל שורת הרצת השלב; תומך בהרצה יבשה. Tree-sitter והדקדוקים שלו הם רכיבי native נדרשים — dylib חסר פירושו שהשרת מעולם לא עלה, ודקדוק שנכשל להיפתר באמצע ההרצה מכשיל את השלב במקום לדלג עליו.
| מפתח מצב | תיאור |
|---|---|
repo_id |
מאגר לאינדוקס (נדרש) |
repo_local_path |
נתיב מקומי של הצ׳קאאוט (נדרש) |
meeting.diarize
קטע בשם “meeting.diarize”הפרדת דוברים במצב לא מקוון. קוראת את האודיו שנשמר של הפגישה, מקבצת אותו לדוברים (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) |
השלב נכשל עם הודעת שגיאה |
StepRetryPolicy
קטע בשם “StepRetryPolicy”התנהגות ניסיון חוזר לגוף צומת שנכשל (PipelineNodeConfig.retryPolicy; null מבטל ניסיונות חוזרים).
| שדה | סוג | תיאור |
|---|---|---|
maxAttempts |
int |
סך הניסיונות כולל הראשון (3 = ניסיון אחד + 2 ניסיונות חוזרים); חייב להיות ≥ 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 (תת־קבוצה) שערך הפלט חייב לעמוד בה |
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'] — מדלג על הצומת כשלא מתקיים).