گامهای پایپلاین
یک گام پایپلاین دو محور مستقل دارد:
- نوع (
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 |
دیدهبان زمانبند بدون بدنه. اجرای پایپلاین هنگامی کامل میشود که یک گام پایانی تمام شود. |
بدنههای گام
بخش با عنوان “بدنههای گام”بستارهای بدنهٔ ثبتشده که با ثابتهای 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 |
کلید حالتی که هنگام خروج با کد 0، stdout پیرایششده را دریافت میکند |
با دایرکتوری جاری <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”بدنهٔ router — 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”یافتههای تجمیعشده را از طریق کلاینت PR مربوط به GitHub بهعنوان یک نظر بازبینی PR منتشر میکند.
| کلید حالت | توضیح |
|---|---|
repo_full_name |
owner/repo (اجباری) |
pr_number |
شمارهٔ PR — عدد صحیح یا رشتهٔ عددی (اجباری) |
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} در یک گفتگو (حالت review) اعزام میکند و سپس تا زمانی که تأییدکننده از راه 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”worktreeهای ایزولهٔ کهنه را حذف میکند؛ حالتش را از بار دادهٔ تریگر برمیدارد. پرچم dryRun اجرا را رعایت میکند.
| کلید حالت | توضیح |
|---|---|
ticket_id |
worktreeهای آن تیکت را آزاد میکند |
repo_full_name + pr_number |
worktree موقت ویرایشگر PR را آزاد میکند |
space_id |
worktreeها و پوشهٔ آن گفتگو را برمیچیند |
| (هیچیک از موارد بالا) | فضای کاری را جاروب میکند: دایرکتوریهای ناپدیدشده، فضاهای مرده، پوشههای گفتگوی یتیم |
outputKey (اختیاری) یک رشتهٔ خلاصه دریافت میکند.
flow.forEach
بخش با عنوان “flow.forEach”Map / پخش روی یک مجموعهٔ حالت: پرامپت را یک بار بهازای هر آیتم رندر میکند، سپس عامل را یک بار با پرامپتهای بههمچسبیده (--- بهعنوان جداکننده) اعزام میکند و تا پایان آن اجرا معلق میماند. یک مجموعهٔ خالی بیدرنگ با فهرستی خالی کامل میشود. این یک اعزام موازی بهازای هر آیتم نیست.
| فیلد پیکربندی | توضیح |
|---|---|
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: مخزن را میپیماید، نمادها/یالها را در ایزولههای کارگر استخراج میکند و آنها را در گراف کد فضای کاری میبلعد. پیشرفت را به ردیف اجرای گام جریان میدهد؛ از dry-run پشتیبانی میکند. tree-sitter و گرامرهایش از بومیهای الزامیاند — نبود یک 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}) |
کاملشدن router؛ شاخهٔ پاییندستیای را انتخاب میکند که 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 تلاش + 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'] — در صورت برآورده نشدن، گره را رد میکند).