Lewati ke konten

Jenis langkah pipeline

Sebuah langkah pipeline memiliki dua sumbu yang independen:

  • Jenis (StepKind) — bagaimana mesin menjadwalkan langkah tersebut relatif terhadap pemicunya.
  • Kunci badan (BuiltInBodyKeys) — closure badan terdaftar mana yang menjalankan pekerjaan langkah itu.

Didefinisikan di packages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart.

Jenis Semantik penjadwalan
trigger Titik masuk wajib — tepat satu per templat, selalu node pertama. Tidak melakukan pekerjaan sendiri; apa yang memulai eksekusi (manual / peristiwa / jadwal) dilacak secara terpisah sebagai baris PipelineTrigger. Badannya adalah pipeline.trigger yang no-op.
listen Terpicu ketika semua langkah sumber (di StepTrigger.sourceStepIds) selesai.
join Terpicu ketika semua langkah di waitForStepIds mencapai status terminal.
router Percabangan bersyarat — badan mengembalikan StepResult.route(key), yang hanya memicu sisi hilir yang routeKey-nya cocok; cabang yang tidak dipilih ditandai dilewati.
forEach Dijadwalkan seperti listen (terpicu ketika semua sourceStepIds selesai). Badan flow.forEach yang terdaftar itulah yang melakukan iterasi; mesin tidak membuat satu langkah anak per item.
terminal Sentin penjadwal tanpa badan. Eksekusi pipeline selesai ketika langkah terminal selesai.

Closure badan terdaftar yang dikunci oleh konstanta di BuiltInBodyKeys (packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart). Ada 25, semuanya tercantum di bawah. Konfigurasi dibaca dari PipelineNodeConfig milik langkah (lihat di bawah) kecuali disebutkan lain; “kunci state” dibaca dari state pipeline / payload pemicu pada saat eksekusi.

Langkah yang bodyKey-nya tidak terdaftar menghasilkan peringatan saat templat dimuat lalu tidak pernah dijalankan — itu tidak menggagalkan eksekusi. Langkah trigger dan terminal dikecualikan dari peringatan itu: pemicu tetap menjalankan badan pipeline.trigger yang no-op; langkah terminal tidak punya badan.

Badan no-op dari node trigger yang wajib — selesai seketika sehingga mesin menyebar ke pendengar di hilir. Tanpa konfigurasi.

Langkah shell tanpa agen (bash -c). Placeholder {{key}} di dalam skrip diganti dari state + payload pemicu dengan nilai yang di-escape untuk shell.

Kolom konfigurasi Keterangan
script Perintah shell yang dijalankan (wajib)
outputKey Kunci state yang menerima stdout yang dipangkas saat keluar dengan kode 0

Dijalankan dengan cwd <cc_root>/pipelines/<pipelineRunId>/ (dipakai bersama oleh semua langkah bash dalam satu eksekusi) dan GITHUB_TOKEN di environment. Juga menulis <stepId>_runDir ke state. Keluar dengan kode bukan nol menggagalkan langkah beserta ekor stderr.

Node prompt-dan-kirim generik: merender prompt, mengirim agen ke sebuah percakapan, dan menangguhkan hingga eksekusi selesai. Payload submit_output agen dipanen ke state di bawah outputKey.

Kolom konfigurasi Keterangan
agentId UUID agen dengan cakupan ruang kerja yang dikirim (wajib)
prompt Teks instruksi; mendukung substitusi {{key}} (wajib)
outputKey Kunci state untuk output yang dipanen
outputSchema JSON Schema yang harus dipenuhi output
label Label untuk manusia yang ditampilkan di kanvas
extras.spaceId Percakapan yang sudah ada untuk bekerja di dalamnya (bawaan: percakapan tersembunyi)
extras.conversationTitle Aliran bernama di dalam space itu (opsional)
extras.mode Dibaca pada node yang membuka ruangan (messaging.createSpace), bukan di sini. Bawaan review.

Badan router — membaca config.extras, mengevaluasi suatu kondisi, dan mengembalikan StepResult.route(key). Kondisi bukan ekspresi JavaScript; tiga bentuk penulisan didukung, dalam urutan prioritas:

  • Pohon predikat (extras.predicate) — pohon boolean yang merutekan "true" / "false". Setiap node adalah peta dengan type:
    • {"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false} — bernilai true ketika salah satu path yang tercantum ada di disk; negate membalikkannya; recursive juga menelusuri subdirektori (melewati .git, node_modules, build, .dart_tool). Path relatif diselesaikan terhadap state[baseKey] (bawaan repo_local_path), jika tidak terhadap direktori ruang kerja per eksekusi.
    • {"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80} — operator equals, notEquals, contains, exists, notExists, gt, lt; membaca state pipeline, bukan sistem berkas.
    • {"type": "and" | "or", "of": [<predicate>, ...]} — grup boolean.
    • {"type": "not", "of": <predicate>} — negasi.
  • Switch (extras.switchKey) — {"switchKey": "pr_class", "cases": [...], "default": "standard"}; merutekan ke case pertama yang memuat nilai state tanpa memedulikan huruf besar/kecil, jika tidak maka default.
  • Perbandingan (warisan tingkat atas extras.left / extras.op / extras.right) — setara dengan predikat comparison, dipertahankan untuk templat yang ditulis sebelum pohon itu.

Sisi yang keluar dari node membawa routeKey yang harus cocok dengan kunci yang dikembalikan.

Memposting temuan gabungan sebagai komentar tinjauan PR melalui klien PR GitHub.

Kunci state Keterangan
repo_full_name owner/repo (wajib)
pr_number Nomor PR — int atau string numerik (wajib)
consolidated_findings Isi komentar (wajib)

Mengembalikan StepResult.terminal dengan comment_review_id dan commented_at di state.

Memposting pesan ke space pesan melalui MessagingPort.

Kunci state Keterangan
space_id Space tujuan (wajib)
content Isi pesan, dibaca apa adanya dari state (wajib)

Menulis posted_space_id dan posted_at ke state.

Mengirim satu tim utuh alih-alih satu agen, lalu menangguhkan hingga eksekusi para anggotanya selesai.

Kolom konfigurasi Keterangan
teamId Tim dengan cakupan ruang kerja yang dikirim (wajib; saling eksklusif dengan agentId)
prompt Teks tujuan; mendukung substitusi {{key}} (wajib)
dispatchMode allParallel (bawaan — satu tugas per anggota) atau manager (hanya mengirim pemimpin untuk mengoordinasikan)
outputKey Kunci state untuk output anggota yang dipanen
outputSchema, label, extras.spaceId Sama seperti conversation.promptAgent

Gerbang persetujuan. Mengirim agen penyetuju ke sebuah percakapan (mode tinjauan) dengan prompt gerbang dan kontrak output {decision, reason}, lalu menangguhkan hingga penyetuju mengirimkan melalui submit_output.

Kolom konfigurasi Keterangan
agentId Agen penyetuju (wajib)
prompt Prompt gerbang (opsional; bawaan dipakai bila tidak ada)
outputKey Kunci state untuk payload {decision, reason} yang dipanen
outputSchema Bawaannya adalah skema persetujuan (decision: approved / rejected, reason)
label, extras.spaceId Sama seperti conversation.promptAgent

Gerbang hanya diselesaikan melalui submit_output. BuiltInBodyKeys.humanGate, pustaka jenis node, dan teks prompt salah satu templat bawaan semuanya menyebut alat MCP approve_step dan reject_step; kedua alat itu tidak ada di paket atau registri mana pun.

Menghapus worktree terisolasi yang sudah usang; memilih modenya dari payload pemicu. Menghormati flag dryRun eksekusi.

Kunci state Keterangan
ticket_id Melepaskan worktree tiket tersebut
repo_full_name + pr_number Melepaskan worktree editor PR yang sementara
space_id Membongkar worktree dan folder percakapan tersebut
(tidak satu pun di atas) Menyapu ruang kerja: direktori yang lenyap, space mati, folder percakapan yatim

outputKey (opsional) menerima string ringkasan.

Pemetaan / fan-out atas koleksi state: merender prompt sekali per item, lalu mengirim agen sekali dengan prompt-prompt itu yang digabungkan (pemisah ---), dan menangguhkan hingga eksekusi itu selesai. Koleksi kosong selesai seketika dengan daftar kosong. Ini bukan satu pengiriman paralel per item.

Kolom konfigurasi Keterangan
agentId Agen yang dikirim per item (wajib)
prompt Prompt per item; mendukung substitusi {{key}} (wajib)
extras.iterableKey Kunci state yang memuat koleksi (wajib)
extras.itemKey Kunci tempat item saat ini diikat di dalam prompt (bawaan item)
outputKey Kunci state untuk output yang dipanen (satu pengiriman, bukan daftar)

Menjalankan templat pipeline lain sebagai sub-langkah bersarang (sub-pipeline berjalan sebagai eksekusi anak dengan parentPipelineRunId terisi). Langkah menangguhkan hingga anak mencapai status terminal, lalu state akhir anak digabungkan di bawah outputKey.

Kolom konfigurasi Keterangan
extras.templateId Templat anak yang dijalankan (wajib; pipeline tidak dapat memanggil dirinya sendiri)
inputKeys Kunci state yang disalin ke payload pemicu anak
outputKey Kunci state untuk state akhir anak yang digabungkan

Pengindeksan tree-sitter di latar belakang: menelusuri sebuah repo, mengekstrak simbol/tepi di isolate pekerja, dan menyerapnya ke dalam graf kode ruang kerja. Mengalirkan progres ke baris eksekusi langkah; mendukung dry-run. Tree-sitter dan grammar-nya adalah native yang wajib — dylib yang hilang berarti server tidak pernah boot, dan grammar yang gagal diselesaikan di tengah eksekusi menggagalkan langkah alih-alih melewatinya.

Kunci state Keterangan
repo_id Repo yang diindeks (wajib)
repo_local_path Path lokal checkout (wajib)

Diarisasi pembicara secara offline. Membaca audio rapat yang disimpan, mengelompokkannya menjadi pembicara (Person 1, Person 2, …), memberi label ulang pada segmen transkrip, dan menulis ulang state transcript; juga mengeluarkan diarization_spans untuk langkah meeting.updateTranscript yang paralel. Meneruskan transkrip tanpa perubahan ketika tidak ada audio yang disimpan atau modelnya belum terpasang.

Kunci state Keterangan
meeting_id Rapat yang didiarisasi (wajib)

meeting.saveNotes, meeting.addActionItems, meeting.addDecisions

Bagian berjudul “meeting.saveNotes, meeting.addActionItems, meeting.addDecisions”

Badan persist ringkasan rapat yang deterministik. Masing-masing membaca meeting_id dan payload meeting_outcome terstruktur dari langkah agen ({summary, enhancedNotes, actionItems[], decisions[]}) dari state, lalu menulis bagiannya ke tabelnya sendiri — catatan, item tindakan, atau keputusan. Baris yang sudah tersimpan tidak pernah dihapus pada eksekusi yang terdegradasi.

Kunci badan Keterangan
meeting.identifySpeakers Pengenalan pembicara lintas rapat: mencocokkan pembicara yang didiarisasi dengan profil suara yang tersimpan dan otomatis menerapkan kecocokan yang meyakinkan. No-op tanpa profil/embedding.
meeting.updateTranscript Menerapkan label Person N dari diarization_spans dan menggabungkan fragmen per jendela menjadi giliran per pembicara, lalu mempersistenkan transkrip yang sudah dibersihkan. No-op ketika diarisasi tidak menghasilkan apa pun.
meeting.assemblePlayback Merakit trek pemutaran campuran rapat dari WAV per kanal yang disimpan. No-op ketika tidak ada audio yang disimpan.
orchestration.markPhase Di akhir DAG pekerjaan, menulis sentinel kegagalan untuk sub-tiket tanpa output dan mengubah orkestrasi ke synthesizing.
orchestration.persistDeliverable Menulis output sintesis ke tiket induk, menyelesaikannya, memposting hasil kerja, dan menandai orkestrasi completed.
orchestration.awaitApproval Gerbang persetujuan sebagian: selesai seketika ketika kunci node langkah ada di himpunan yang disetujui orkestrasi, jika tidak menangguhkan hingga persetujuan berikutnya melanjutkannya. Ini satu-satunya badan yang menetapkan extras.awaitApproval, yang membebaskannya dari timeout 24 jam untuk langkah yang ditangguhkan.
messaging.createSpace Membuka percakapan tempat sisa templat bekerja, yang dipublikasikan di bawah outputKey langkah (bawaan menggunakan pipeline_space_id). Daftar repoIds yang kosong tidak men-checkout apa pun; extras['allRepos'] men-checkout setiap repo ruang kerja. extras['createConversation'] (mati secara bawaan) juga membuka aliran bernama. Langkah agen BERGABUNG ke sebuah ruangan dan tidak pernah membukanya, jadi fan-out tanpa node ini gagal saat pengiriman — dan memasangnya sekali berarti seluruh fan-out berbagi satu checkout alih-alih menyediakan satu untuk masing-masing.
prReview.finalize Langkah terakhir templat tinjauan PR: menyortir node tinjauan yang terkumpul ke dalam keranjang konsensus dan menghitung putusan per PR.
skills.analyze Menjalankan pemindaian rantai pasok skill atas skill yang terpasang di ruang kerja dan mencatat setiap putusan.

Badan langkah mengembalikan StepResult (packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart). Semua factory menerima peta mutatedState opsional yang digabungkan ke state pipeline, kecuali failed.

Factory Tanda tangan Keterangan
ok StepResult.ok({mutatedState}) Penyelesaian normal; pendengar di hilir dievaluasi
route StepResult.route(nextRouterKey, {mutatedState}) Penyelesaian router; memilih cabang hilir yang routeKey-nya cocok
suspendUntilEvent StepResult.suspendUntilEvent(eventType, {mutatedState}) Menjeda hingga jenis peristiwa domain tertentu terpicu
suspendUntilTasksComplete StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) Menjeda hingga semua tugas yang tercantum mencapai status terminal
terminal StepResult.terminal({mutatedState}) Eksekusi pipeline selesai — tidak ada langkah lagi
failed StepResult.failed(errorMessage) Langkah gagal dengan pesan error

Perilaku percobaan ulang untuk badan node yang gagal (PipelineNodeConfig.retryPolicy; null menonaktifkan percobaan ulang).

Kolom Jenis Keterangan
maxAttempts int Total percobaan termasuk yang pertama (3 = 1 percobaan + 2 percobaan ulang); harus ≥ 1
backoff String linear atau exponential (bawaan)
initialDelayMs int Jeda sebelum percobaan ulang pertama, dalam milidetik; jeda berikutnya bertambah sesuai backoff

Konfigurasi per node yang dibawa di dalam definisi langkah (packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart). Node bawaan maupun kustom memakai bentuk yang sama; setiap badan hanya membaca kolom yang diperlukannya.

Kolom Jenis Keterangan
prompt String? Templat prompt dengan substitusi {{key}}
script String? Badan skrip bash dengan substitusi {{key}}
agentId String? UUID agen dengan cakupan ruang kerja yang dikirim
inputKeys List<String> Kunci state yang dikonsumsi node ini sebagai input
repoIds List<String> Repo yang di-checkout node messaging.createSpace (<repoId> atau <repoId>@<branch>). Kosong = tidak ada; extras['allRepos'] = setiap repo ruang kerja. Diabaikan pada langkah agen.
outputKey String? Kunci state tempat output node ini ditulis
label String? Label untuk manusia yang ditampilkan di kanvas (bawaannya ID langkah)
outputSchema Map<String, dynamic>? JSON Schema (subset) yang harus dipenuhi nilai output
reducer String? Strategi penggabungan ketika cabang paralel menulis outputKey yang sama: append, mergeLists, mergeMaps, sum, atau override (bawaan)
retryPolicy StepRetryPolicy? Kebijakan percobaan ulang saat badan gagal; null = satu percobaan
continueOnFail bool Jika true, kegagalan terminal tidak menggagalkan eksekusi; error-nya disimpan di bawah state['_stepErrors'][stepId]
timeoutMs int? Timeout waktu nyata untuk badan node dalam milidetik; null = tanpa timeout
teamId String? Tim yang dikirim (node team.dispatch); saling eksklusif dengan agentId
dispatchMode String? Mode eksekusi tim: allParallel atau manager
extras Map<String, dynamic> Konfigurasi khusus badan yang bebas (mis. iterableKey, templateId, pohon kondisi)

Aksesor turunan: spaceId (extras['spaceId'] — percakapan yang sudah ada untuk bekerja di dalamnya), createsConversation (extras['createConversation']), conversationTitle (extras['conversationTitle']), modeName (extras['mode'] — chat / review / plan, dibaca pada node pembuka space) dan runWhen (extras['runWhen'] — lewati node ketika tidak terpenuhi).