Typy kroků pipeline
Krok pipeline má dvě na sobě nezávislé osy:
- Druh (
StepKind) — jak engine krok vůči jeho spouštěčům naplánuje. - Klíč těla (
BuiltInBodyKeys) — který registrovaný uzávěr těla práci kroku provede.
Druhy kroků
Sekce “Druhy kroků”Definováno v packages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart.
| Druh | Sémantika plánování |
|---|---|
trigger |
Povinný vstupní bod — v šabloně právě jeden, vždy první uzel. Sám nic neudělá; co běh spustilo (ručně / událost / plán), se eviduje zvlášť jako řádky PipelineTrigger. Jeho tělo je prázdné pipeline.trigger. |
listen |
Spustí se, když se dokončí všechny zdrojové kroky (v StepTrigger.sourceStepIds). |
join |
Spustí se, když všechny kroky v waitForStepIds dojdou do koncového stavu. |
router |
Podmíněné větvení — tělo vrátí StepResult.route(key), což vystřelí jen navazující hranu, jejíž routeKey sedí; nevybrané větve se označí jako přeskočené. |
forEach |
Plánuje se jako listen (spustí se, když se dokončí všechna sourceStepIds). Iteruje registrované tělo flow.forEach; engine nezaloží jeden podřízený krok na položku. |
terminal |
Zarážka plánovače bez těla. Běh pipeline se dokončí, když skončí krok terminal. |
Těla kroků
Sekce “Těla kroků”Registrované uzávěry těl podle konstant v BuiltInBodyKeys (packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart). Je jich 25 a všechny jsou níže. Konfigurace se čte z PipelineNodeConfig kroku (viz níže), pokud není uvedeno jinak; „stavové klíče“ se při provedení čtou ze stavu pipeline a z payloadu spouštěče.
Krok, jehož bodyKey není registrovaný, při načtení šablony varuje a pak se nikdy nespustí — běh tím neselže. Kroky trigger a terminal tohle varování nemají: trigger pořád spustí prázdné tělo pipeline.trigger; krok terminal tělo nemá.
pipeline.trigger
Sekce “pipeline.trigger”Prázdné tělo povinného uzlu trigger — dokončí se hned, aby se engine rozvětvil k navazujícím posluchačům. Bez konfigurace.
pipeline.bashScript
Sekce “pipeline.bashScript”Shellový krok bez agenta (bash -c). Zástupné symboly {{key}} ve skriptu se dosadí ze stavu a z payloadu spouštěče, s hodnotami escapovanými pro shell.
| Pole konfigurace | Popis |
|---|---|
script |
Shellový příkaz ke spuštění (povinné) |
outputKey |
Stavový klíč, který při exitu 0 dostane ořezaný stdout |
Běží s cwd <cc_root>/pipelines/<pipelineRunId>/ (sdílí ho všechny bash kroky v běhu) a s GITHUB_TOKEN v prostředí. Do stavu taky zapíše <stepId>_runDir. Nenulový exit krok shodí a přiloží konec stderr.
conversation.promptAgent
Sekce “conversation.promptAgent”Obecný uzel pro prompt a odeslání: vykreslí prompt, odešle agenta do konverzace a pozastaví se, dokud běh neskončí. Payload z submit_output agenta se zapíše do stavu pod outputKey.
| Pole konfigurace | Popis |
|---|---|
agentId |
UUID agenta v rozsahu pracovního prostoru k odeslání (povinné) |
prompt |
Text instrukce; umí dosazení {{key}} (povinné) |
outputKey |
Stavový klíč pro sebraný výstup |
outputSchema |
JSON Schema, kterou musí výstup splnit |
label |
Lidský popisek na plátně |
extras.spaceId |
Existující konverzace, ve které se pracuje (výchozí: skrytá) |
extras.conversationTitle |
Pojmenovaný proud uvnitř toho prostoru (volitelné) |
extras.mode |
Čte se na uzlu, který prostor otevírá (messaging.createSpace), ne tady. Výchozí review. |
pipeline.condition
Sekce “pipeline.condition”Tělo routeru — přečte config.extras, vyhodnotí podmínku a vrátí StepResult.route(key). Podmínky nejsou výrazy JavaScriptu; podporované jsou tři tvary zápisu, v tomhle pořadí priority:
- Strom predikátů (
extras.predicate) — booleovský strom, který vede na"true"/"false". Každý uzel je mapa stype:{"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false}— platí, když na disku existuje kterákoli uvedená cesta;negateto obrátí;recursivehledá i v podadresářích (přeskočí.git,node_modules,build,.dart_tool). Relativní cesty se vyhodnotí vůčistate[baseKey](výchozírepo_local_path), jinak vůči adresáři pracovního prostoru daného běhu.{"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80}— operátoryequals,notEquals,contains,exists,notExists,gt,lt; čte stav pipeline, ne souborový systém.{"type": "and" | "or", "of": [<predicate>, ...]}— booleovské skupiny.{"type": "not", "of": <predicate>}— negace.
- Přepínač (
extras.switchKey) —{"switchKey": "pr_class", "cases": [...], "default": "standard"}; vede na první případ, jehož řetězec hodnota stavu obsahuje bez ohledu na velikost písmen, jinak nadefault. - Porovnání (starší zápis nahoře v
extras.left/extras.op/extras.right) — odpovídá predikátucomparisona zůstává kvůli šablonám napsaným před stromem.
Hrany vycházející z uzlu nesou routeKey, který se musí shodovat s vráceným klíčem.
prReview.comment
Sekce “prReview.comment”Pošle sloučená zjištění jako komentář k revizi PR přes klienta GitHub PR.
| Stavový klíč | Popis |
|---|---|
repo_full_name |
owner/repo (povinné) |
pr_number |
Číslo PR — int, nebo číselný řetězec (povinné) |
consolidated_findings |
Tělo komentáře (povinné) |
Vrátí StepResult.terminal a do stavu zapíše comment_review_id a commented_at.
messaging.postSpace
Sekce “messaging.postSpace”Pošle zprávu do prostoru pro zprávy přes MessagingPort.
| Stavový klíč | Popis |
|---|---|
space_id |
Cílový prostor (povinné) |
content |
Tělo zprávy, ze stavu se čte doslovně (povinné) |
Do stavu zapíše posted_space_id a posted_at.
team.dispatch
Sekce “team.dispatch”Odešle celý tým místo jednoho agenta a pozastaví se, dokud běhy členů neskončí.
| Pole konfigurace | Popis |
|---|---|
teamId |
Tým v rozsahu pracovního prostoru k odeslání (povinné; s agentId se vzájemně vylučuje) |
prompt |
Text cíle; umí dosazení {{key}} (povinné) |
dispatchMode |
allParallel (výchozí — jeden úkol na člena) nebo manager (odešle jen vedoucího, aby koordinoval) |
outputKey |
Stavový klíč pro sebrané výstupy členů |
outputSchema, label, extras.spaceId |
Stejně jako u conversation.promptAgent |
human.gate
Sekce “human.gate”Schvalovací brána. Odešle schvalujícího agenta do konverzace (režim review) s promptem brány a výstupním kontraktem {decision, reason} a pozastaví se, dokud schvalovatel neodešle výsledek přes submit_output.
| Pole konfigurace | Popis |
|---|---|
agentId |
Schvalující agent (povinné) |
prompt |
Prompt brány (volitelné; když chybí, použije se výchozí) |
outputKey |
Stavový klíč pro sebraný payload {decision, reason} |
outputSchema |
Výchozí je schvalovací schéma (decision: approved / rejected, reason) |
label, extras.spaceId |
Stejně jako u conversation.promptAgent |
Brána se vyřeší jen přes submit_output. BuiltInBodyKeys.humanGate, knihovna typů uzlů i text promptu jedné vestavěné šablony jmenují nástroje MCP approve_step a reject_step; ani jeden nástroj neexistuje v žádném balíčku ani registru.
repos.cleanup
Sekce “repos.cleanup”Odstraní zastaralé izolované worktree; režim si vybere z payloadu spouštěče. Respektuje příznak dryRun běhu.
| Stavový klíč | Popis |
|---|---|
ticket_id |
Uvolní worktree toho ticketu |
repo_full_name + pr_number |
Uvolní dočasný worktree editoru PR |
space_id |
Zruší worktree a složku té konverzace |
| (nic z výše uvedeného) | Projde pracovní prostor: zmizelé adresáře, mrtvé prostory, osiřelé složky konverzací |
outputKey (volitelné) dostane souhrnný řetězec.
flow.forEach
Sekce “flow.forEach”Mapování / fan-out nad kolekcí ve stavu: prompt vykreslí jednou pro každou položku, pak agenta odešle jednou s těmi prompty zřetězenými (oddělovače ---) a pozastaví se, dokud ten běh neskončí. Prázdná kolekce hned skončí prázdným seznamem. Není to jedno paralelní odeslání na položku.
| Pole konfigurace | Popis |
|---|---|
agentId |
Agent k odeslání na každou položku (povinné) |
prompt |
Prompt na položku; umí dosazení {{key}} (povinné) |
extras.iterableKey |
Stavový klíč, který drží kolekci (povinné) |
extras.itemKey |
Klíč, na který se v promptu naváže aktuální položka (výchozí item) |
outputKey |
Stavový klíč pro sebraný výstup (jedno odeslání, ne seznam) |
flow.callPipeline
Sekce “flow.callPipeline”Spustí jinou šablonu pipeline jako vnořený podkrok (podpipeline běží jako podřízený běh s nastaveným parentPipelineRunId). Krok se pozastaví, dokud podřízený běh nedojde do koncového stavu, a pak se jeho konečný stav sloučí pod outputKey.
| Pole konfigurace | Popis |
|---|---|
extras.templateId |
Podřízená šablona ke spuštění (povinné; pipeline nemůže volat sama sebe) |
inputKeys |
Stavové klíče zkopírované do payloadu spouštěče podřízeného běhu |
outputKey |
Stavový klíč pro sloučený konečný stav podřízeného běhu |
code.index
Sekce “code.index”Indexování tree-sitter na pozadí: projde repozitář, v izolátech workerů vytáhne symboly a hrany a vloží je do grafu kódu pracovního prostoru. Průběh streamuje do řádku běhu kroku; umí dry-run. Tree-sitter a jeho gramatiky jsou povinné nativy — chybějící dylib znamená, že se server nikdy nespustil, a gramatika, která se v půlce běhu nepodaří načíst, krok shodí, místo aby ho přeskočila.
| Stavový klíč | Popis |
|---|---|
repo_id |
Repozitář k indexování (povinné) |
repo_local_path |
Lokální cesta checkoutu (povinné) |
meeting.diarize
Sekce “meeting.diarize”Offline diarizace řečníků. Přečte ponechané audio schůzky, seskupí ho do řečníků (Person 1, Person 2, …), přeznačí segmenty přepisu a přepíše stav transcript; pro paralelní krok meeting.updateTranscript taky vyprodukuje diarization_spans. Když se audio neponechalo nebo nejsou nainstalované modely, přepis propustí beze změny.
| Stavový klíč | Popis |
|---|---|
meeting_id |
Schůzka k diarizaci (povinné) |
meeting.saveNotes, meeting.addActionItems, meeting.addDecisions
Sekce “meeting.saveNotes, meeting.addActionItems, meeting.addDecisions”Deterministická těla pro uložení shrnutí schůzky. Každé si ze stavu přečte meeting_id a strukturovaný payload meeting_outcome z kroku agenta ({summary, enhancedNotes, actionItems[], decisions[]}) a svou část zapíše do vlastní tabulky — poznámky, akční položky, nebo rozhodnutí. Dříve uložené řádky se při zhoršeném běhu nikdy nemažou.
Další vestavěná těla
Sekce “Další vestavěná těla”| Klíč těla | Popis |
|---|---|
meeting.identifySpeakers |
Rozpoznání řečníků napříč schůzkami: diarizované řečníky porovná s uloženými hlasovými profily a jisté shody uplatní samo. Bez profilů a embeddingů nic neudělá. |
meeting.updateTranscript |
Aplikuje popisky Person N z diarization_spans a sloučí fragmenty po oknech do replik podle řečníka, pak uloží vyčištěný přepis. Když diarizace nic nevyprodukovala, nic neudělá. |
meeting.assemblePlayback |
Složí smíšenou stopu přehrávání schůzky z ponechaných WAV po kanálech. Když se audio neponechalo, nic neudělá. |
orchestration.markPhase |
Na konci pracovního DAGu zapíše zarážky selhání pro podtickety bez výstupu a přepne orchestaci na synthesizing. |
orchestration.persistDeliverable |
Zapíše výstup syntézy na nadřazený ticket, dokončí ho, zveřejní výstup a označí orchestaci jako completed. |
orchestration.awaitApproval |
Brána částečného schválení: dokončí se hned, když je klíč uzlu kroku ve schválené množině orchetrace, jinak se pozastaví, dokud ho pozdější schválení neobnoví. Je to jediné tělo, které nastavuje extras.awaitApproval, a tím se vyjímá z 24hodinového timeoutu pozastaveného kroku. |
messaging.createSpace |
Otevře konverzaci, ve které pracuje zbytek šablony, a zveřejní ji pod outputKey kroku (vestavěné používají pipeline_space_id). Prázdný seznam repoIds nic necheckoutuje; extras['allRepos'] checkoutne každý repozitář pracovního prostoru. extras['createConversation'] (ve výchozím stavu vypnuté) navíc otevře pojmenovaný proud. Krok agenta do místnosti VSTOUPÍ a nikdy ji neotevře, takže fan-out bez tohoto uzlu spadne při odeslání — a když ho zapojíš jednou, celý fan-out sdílí jeden checkout, místo aby se připravoval jeden pro každý. |
prReview.finalize |
Poslední krok šablony revize PR: nashromážděné uzly revize roztřídí do košů podle konsenzu a spočítá verdikt na PR. |
skills.analyze |
Spustí kontrolu dodavatelského řetězce skillů nad nainstalovanými skilly pracovního prostoru a zaznamená každý verdikt. |
Výsledky kroků
Sekce “Výsledky kroků”Tělo kroku vrací StepResult (packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart). Všechny továrny berou volitelnou mapu mutatedState, která se sloučí do stavu pipeline, kromě failed.
| Továrna | Signatura | Popis |
|---|---|---|
ok |
StepResult.ok({mutatedState}) |
Běžné dokončení; vyhodnotí se navazující posluchači |
route |
StepResult.route(nextRouterKey, {mutatedState}) |
Dokončení routeru; vybere navazující větev, jejíž routeKey sedí |
suspendUntilEvent |
StepResult.suspendUntilEvent(eventType, {mutatedState}) |
Pozastavení, dokud nevyletí konkrétní typ doménové události |
suspendUntilTasksComplete |
StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) |
Pozastavení, dokud všechny uvedené úlohy nedojdou do koncového stavu |
terminal |
StepResult.terminal({mutatedState}) |
Běh pipeline je hotový — žádné další kroky |
failed |
StepResult.failed(errorMessage) |
Krok selhal s chybovou zprávou |
StepRetryPolicy
Sekce “StepRetryPolicy”Chování opakování pro selhávající tělo uzlu (PipelineNodeConfig.retryPolicy; null opakování vypne).
| Pole | Typ | Popis |
|---|---|---|
maxAttempts |
int |
Celkový počet pokusů včetně prvního (3 = 1 pokus + 2 opakování); musí být ≥ 1 |
backoff |
String |
linear nebo exponential (výchozí) |
initialDelayMs |
int |
Prodleva před prvním opakováním v milisekundách; další prodlevy rostou podle backoff |
PipelineNodeConfig
Sekce “PipelineNodeConfig”Konfigurace jednoho uzlu nesená uvnitř definice kroku (packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart). Vestavěné i vlastní uzly sdílejí tenhle tvar; každé tělo čte jen pole, která potřebuje.
| Pole | Typ | Popis |
|---|---|---|
prompt |
String? |
Šablona promptu s dosazením {{key}} |
script |
String? |
Tělo bash skriptu s dosazením {{key}} |
agentId |
String? |
UUID agenta v rozsahu pracovního prostoru k odeslání |
inputKeys |
List<String> |
Stavové klíče, které tenhle uzel bere jako vstup |
repoIds |
List<String> |
Repozitáře, které checkoutne uzel messaging.createSpace (<repoId> nebo <repoId>@<branch>). Prázdné = žádný; extras['allRepos'] = každý repozitář pracovního prostoru. Na krocích agenta se ignoruje. |
outputKey |
String? |
Stavový klíč, pod který se zapíše výstup tohohle uzlu |
label |
String? |
Lidský popisek na plátně (výchozí je ID kroku) |
outputSchema |
Map<String, dynamic>? |
JSON Schema (podmnožina), kterou musí výstupní hodnota splnit |
reducer |
String? |
Strategie sloučení, když paralelní větve zapisují stejný outputKey: append, mergeLists, mergeMaps, sum, nebo override (výchozí) |
retryPolicy |
StepRetryPolicy? |
Politika opakování při selhání těla; null = jeden pokus |
continueOnFail |
bool |
Když je true, koncové selhání běh neshodí; chyba se odloží pod state['_stepErrors'][stepId] |
timeoutMs |
int? |
Časový limit těla uzlu v milisekundách reálného času; null = bez limitu |
teamId |
String? |
Tým k odeslání (uzly team.dispatch); s agentId se vzájemně vylučuje |
dispatchMode |
String? |
Režim běhu týmu: allParallel nebo manager |
extras |
Map<String, dynamic> |
Volná konfigurace specifická pro tělo (např. iterableKey, templateId, stromy podmínek) |
Odvozené přístupy: spaceId (extras['spaceId'] — existující konverzace, ve které se pracuje), createsConversation (extras['createConversation']), conversationTitle (extras['conversationTitle']), modeName (extras['mode'] — chat / review / plan, čte se na uzlu, který prostor otevírá) a runWhen (extras['runWhen'] — přeskočí uzel, když podmínka neplatí).