Bỏ qua để đến nội dung

Các bước quy trình

Một bước quy trình có hai trục độc lập:

  • Kind (StepKind) — cách engine lập lịch bước so với các trình kích hoạt của nó.
  • Khóa body (BuiltInBodyKeys) — closure body đã đăng ký nào thực thi công việc của bước.

Được định nghĩa trong packages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart.

Kind Ngữ nghĩa lập lịch
trigger Điểm vào bắt buộc — đúng một cái cho mỗi mẫu, luôn là nút đầu tiên. Bản thân nó không làm gì; thứ khởi chạy lần chạy (thủ công / sự kiện / theo lịch) được theo dõi riêng dưới dạng các hàng PipelineTrigger. Body của nó là body rỗng pipeline.trigger.
listen Kích hoạt khi mọi bước nguồn (trong StepTrigger.sourceStepIds) hoàn tất.
join Kích hoạt khi mọi bước trong waitForStepIds đạt trạng thái kết thúc.
router Rẽ nhánh có điều kiện — body trả về StepResult.route(key), và chỉ cạnh hạ nguồn có routeKey khớp mới được kích hoạt; những nhánh không được chọn bị đánh dấu là bị bỏ qua.
forEach Được lập lịch giống listen (kích hoạt khi mọi sourceStepIds hoàn tất). Chính body flow.forEach đã đăng ký mới là thứ lặp; engine không sinh ra một bước con cho mỗi mục.
terminal Điểm đánh dấu cho bộ lập lịch, không có body. Lần chạy quy trình hoàn tất khi một bước terminal kết thúc.

Các closure body được đăng ký theo những hằng số trong BuiltInBodyKeys (packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart). Có 25 body, tất cả được liệt kê dưới đây. Cấu hình được đọc từ PipelineNodeConfig của bước (xem bên dưới) trừ khi có ghi chú khác; “khóa trạng thái” được đọc từ trạng thái quy trình / payload trình kích hoạt tại thời điểm thực thi.

Một bước có bodyKey không được đăng ký sẽ tạo cảnh báo lúc nạp mẫu rồi sau đó không bao giờ thực thi — nó không làm lần chạy thất bại. Các bước trigger và terminal được miễn cảnh báo đó: trigger vẫn chạy body rỗng pipeline.trigger; còn bước terminal không có body.

Body rỗng của nút trigger bắt buộc — hoàn tất ngay để engine tỏa ra các listener hạ nguồn. Không có cấu hình.

Bước shell không cần agent (bash -c). Các placeholder {{key}} trong script được thay bằng giá trị đã escape cho shell, lấy từ trạng thái + payload trình kích hoạt.

Trường cấu hình Mô tả
script Lệnh shell cần thực thi (bắt buộc)
outputKey Khóa trạng thái nhận stdout đã cắt khoảng trắng khi thoát với mã 0

Chạy với cwd <cc_root>/pipelines/<pipelineRunId>/ (dùng chung cho mọi bước bash trong một lần chạy) và GITHUB_TOKEN trong môi trường. Cũng ghi <stepId>_runDir vào trạng thái. Thoát với mã khác 0 làm bước thất bại kèm phần đuôi stderr.

Nút tổng quát gửi prompt rồi điều phối: kết xuất prompt, điều phối agent vào một hội thoại rồi tạm dừng cho đến khi lần chạy kết thúc. Payload submit_output của agent được thu về trạng thái dưới outputKey.

Trường cấu hình Mô tả
agentId UUID của agent trong không gian làm việc sẽ được điều phối (bắt buộc)
prompt Văn bản hướng dẫn; hỗ trợ thay thế {{key}} (bắt buộc)
outputKey Khóa trạng thái cho đầu ra đã thu về
outputSchema JSON Schema mà đầu ra phải thỏa mãn
label Nhãn cho người dùng hiển thị trên canvas
extras.spaceId Hội thoại đã có để làm việc trong đó (mặc định: một hội thoại ẩn)
extras.conversationTitle Stream có tên bên trong space đó (tùy chọn)
extras.mode Được đọc trên nút mở phòng (messaging.createSpace), không phải ở đây. Mặc định review.

Body router — đọc config.extras, đánh giá một điều kiện rồi trả về StepResult.route(key). Điều kiện không phải biểu thức JavaScript; có ba cách viết được hỗ trợ, theo thứ tự ưu tiên:

  • Cây vị từ (extras.predicate) — một cây boolean định tuyến "true" / "false". Mỗi nút là một map có một type:
    • {"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false} — đúng khi bất kỳ đường dẫn nào được liệt kê tồn tại trên đĩa; negate đảo ngược kết quả; recursive cũng tìm trong các thư mục con (bỏ qua .git, node_modules, build, .dart_tool). Đường dẫn tương đối được giải dựa trên state[baseKey] (mặc định repo_local_path), nếu không thì dựa trên thư mục không gian làm việc của từng lần chạy.
    • {"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80} — các toán tử equals, notEquals, contains, exists, notExists, gt, lt; đọc trạng thái quy trình chứ không đọc hệ thống tệp.
    • {"type": "and" | "or", "of": [<predicate>, ...]} — các nhóm boolean.
    • {"type": "not", "of": <predicate>} — phủ định.
  • Switch (extras.switchKey) — {"switchKey": "pr_class", "cases": [...], "default": "standard"}; định tuyến tới case đầu tiên mà giá trị trạng thái chứa nó (không phân biệt hoa thường), nếu không thì tới default.
  • So sánh (các khóa cấp cao nhất extras.left / extras.op / extras.right kiểu cũ) — tương đương một vị từ comparison, được giữ lại cho những mẫu được viết trước khi có cây vị từ.

Các cạnh đi ra khỏi nút mang một routeKey phải khớp với khóa được trả về.

Đăng các phát hiện đã tổng hợp dưới dạng bình luận đánh giá PR qua máy khách PR của GitHub.

Khóa trạng thái Mô tả
repo_full_name owner/repo (bắt buộc)
pr_number Số PR — số nguyên hoặc chuỗi số (bắt buộc)
consolidated_findings Nội dung bình luận (bắt buộc)

Trả về StepResult.terminal với comment_review_id và commented_at trong trạng thái.

Gửi một tin nhắn tới một không gian nhắn tin qua MessagingPort.

Khóa trạng thái Mô tả
space_id Không gian đích (bắt buộc)
content Nội dung tin nhắn, được đọc nguyên văn từ trạng thái (bắt buộc)

Ghi posted_space_id và posted_at vào trạng thái.

Điều phối cả một đội thay vì một agent đơn lẻ, rồi tạm dừng cho đến khi các lần chạy của các thành viên kết thúc.

Trường cấu hình Mô tả
teamId Đội thuộc không gian làm việc sẽ được điều phối (bắt buộc; loại trừ lẫn nhau với agentId)
prompt Văn bản mục tiêu; hỗ trợ thay thế {{key}} (bắt buộc)
dispatchMode allParallel (mặc định — một tác vụ cho mỗi thành viên) hoặc manager (chỉ điều phối trưởng nhóm để phối hợp)
outputKey Khóa trạng thái cho đầu ra đã thu về của các thành viên
outputSchema, label, extras.spaceId Như đối với conversation.promptAgent

Cổng phê duyệt. Điều phối agent phê duyệt vào một hội thoại (chế độ review) với prompt của cổng và một hợp đồng đầu ra {decision, reason}, rồi tạm dừng cho đến khi agent phê duyệt gửi kết quả qua submit_output.

Trường cấu hình Mô tả
agentId Agent phê duyệt (bắt buộc)
prompt Prompt của cổng (tùy chọn; dùng một giá trị mặc định khi bỏ trống)
outputKey Khóa trạng thái cho payload {decision, reason} đã thu về
outputSchema Mặc định là một lược đồ phê duyệt (decision: approved / rejected, reason)
label, extras.spaceId Như đối với conversation.promptAgent

Cổng chỉ được giải quyết qua submit_output. BuiltInBodyKeys.humanGate, thư viện loại nút và văn bản prompt của một mẫu tích hợp sẵn đều nhắc tới hai công cụ MCP approve_step và reject_step; cả hai công cụ này đều không tồn tại trong bất kỳ package hay registry nào.

Gỡ các worktree cách ly cũ; chọn chế độ của nó từ payload trình kích hoạt. Tuân theo cờ dryRun của lần chạy.

Khóa trạng thái Mô tả
ticket_id Giải phóng worktree của phiếu đó
repo_full_name + pr_number Giải phóng worktree tạm thời của trình chỉnh sửa PR
space_id Tháo dỡ worktree và thư mục của hội thoại đó
(không có mục nào ở trên) Quét toàn không gian làm việc: các thư mục đã biến mất, space đã chết, thư mục hội thoại mồ côi

outputKey (tùy chọn) nhận một chuỗi tóm tắt.

Map / fan-out trên một tập hợp trong trạng thái: kết xuất prompt một lần cho mỗi mục, rồi điều phối agent một lần với các prompt đó được ghép lại (ngăn cách bằng ---) và tạm dừng cho đến khi lần chạy đó kết thúc. Một tập hợp rỗng hoàn tất ngay với một danh sách rỗng. Đây không phải là một lần điều phối song song cho mỗi mục.

Trường cấu hình Mô tả
agentId Agent được điều phối cho mỗi mục (bắt buộc)
prompt Prompt cho mỗi mục; hỗ trợ thay thế {{key}} (bắt buộc)
extras.iterableKey Khóa trạng thái chứa tập hợp (bắt buộc)
extras.itemKey Khóa mà mục hiện tại được gán vào trong prompt (mặc định item)
outputKey Khóa trạng thái cho đầu ra đã thu về (một lần điều phối, không phải một danh sách)

Chạy một mẫu quy trình khác như một bước con lồng nhau (quy trình con chạy như một lần chạy con với parentPipelineRunId được đặt). Bước này tạm dừng cho đến khi con đạt trạng thái kết thúc, rồi trạng thái cuối của con được hợp nhất dưới outputKey.

Trường cấu hình Mô tả
extras.templateId Mẫu con cần chạy (bắt buộc; một quy trình không thể tự gọi chính nó)
inputKeys Các khóa trạng thái được sao chép vào payload trình kích hoạt của con
outputKey Khóa trạng thái cho trạng thái cuối đã hợp nhất của con

Đánh chỉ mục tree-sitter chạy nền: duyệt một kho mã, trích xuất symbol/cạnh trong các isolate worker rồi nạp chúng vào đồ thị mã của không gian làm việc. Truyền tiến độ vào hàng bước của lần chạy; hỗ trợ chạy thử. Tree-sitter và các grammar của nó là native bắt buộc — thiếu một dylib nghĩa là máy chủ chưa từng khởi động, và một grammar không giải được giữa chừng sẽ làm bước thất bại thay vì bị bỏ qua.

Khóa trạng thái Mô tả
repo_id Kho mã cần đánh chỉ mục (bắt buộc)
repo_local_path Đường dẫn cục bộ của bản checkout (bắt buộc)

Phân tách người nói ngoại tuyến. Đọc âm thanh được lưu giữ của cuộc họp, gom cụm thành các người nói (Person 1, Person 2, …), dán nhãn lại các đoạn phiên âm và ghi lại trạng thái transcript; đồng thời phát ra diarization_spans cho bước meeting.updateTranscript chạy song song. Giữ nguyên phiên âm khi không có âm thanh nào được lưu giữ hoặc khi các mô hình chưa được cài đặt.

Khóa trạng thái Mô tả
meeting_id Cuộc họp cần phân tách người nói (bắt buộc)

meeting.saveNotes, meeting.addActionItems, meeting.addDecisions

Phần tiêu đề “meeting.saveNotes, meeting.addActionItems, meeting.addDecisions”

Các body lưu bền tóm tắt cuộc họp một cách tất định. Mỗi body đọc meeting_id và payload meeting_outcome có cấu trúc của bước agent ({summary, enhancedNotes, actionItems[], decisions[]}) từ trạng thái rồi ghi phần của mình vào bảng riêng — ghi chú, mục hành động hoặc quyết định. Các hàng đã lưu trước đó không bao giờ bị xóa khi lần chạy suy giảm.

Khóa body Mô tả
meeting.identifySpeakers Nhận dạng người nói xuyên cuộc họp: đối chiếu những người nói đã được phân tách với các hồ sơ giọng nói đã lưu và tự động áp dụng những kết quả khớp đủ tin cậy. Không làm gì khi thiếu hồ sơ/embedding.
meeting.updateTranscript Áp dụng các nhãn Person N từ diarization_spans và hợp nhất các mảnh của từng cửa sổ thành lượt nói theo từng người nói, rồi lưu bền phiên âm đã làm sạch. Không làm gì khi phân tách người nói không tạo ra kết quả nào.
meeting.assemblePlayback Ghép bản âm thanh phát lại đã trộn của cuộc họp từ các tệp WAV theo kênh được lưu giữ. Không làm gì khi không có âm thanh nào được lưu giữ.
orchestration.markPhase Ở cuối DAG công việc, ghi các dấu hiệu thất bại cho những phiếu con không có đầu ra và chuyển điều phối sang synthesizing.
orchestration.persistDeliverable Ghi đầu ra tổng hợp vào phiếu cha, hoàn tất phiếu đó, đăng kết quả bàn giao và đánh dấu điều phối là completed.
orchestration.awaitApproval Cổng phê duyệt một phần: hoàn tất ngay khi khóa nút của bước nằm trong tập đã được phê duyệt của điều phối, nếu không thì tạm dừng cho đến khi một lần phê duyệt sau đó đánh thức nó. Đây là body duy nhất đặt extras.awaitApproval, và điều đó giúp nó được miễn thời gian chờ 24 giờ dành cho bước bị tạm dừng.
messaging.createSpace Mở hội thoại mà phần còn lại của mẫu làm việc trong đó, được công bố dưới outputKey của bước (các mẫu tích hợp sẵn dùng pipeline_space_id). Danh sách repoIds rỗng thì không checkout gì cả; extras['allRepos'] checkout mọi kho mã của không gian làm việc. extras['createConversation'] (mặc định tắt) cũng mở một stream có tên. Một bước agent THAM GIA một phòng và không bao giờ tự mở phòng, nên một đợt fan-out thiếu nút này sẽ thất bại lúc điều phối — và nối nó một lần nghĩa là cả đợt fan-out dùng chung một bản checkout thay vì cấp riêng cho từng cái.
prReview.finalize Bước cuối cùng của mẫu đánh giá PR: sắp xếp các node đánh giá đã tích lũy vào các nhóm đồng thuận và tính kết luận cho từng PR.
skills.analyze Chạy quét chuỗi cung ứng skill trên các skill đã cài đặt của một không gian làm việc và ghi lại từng phán quyết.

Một body của bước trả về StepResult (packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart). Tất cả các factory đều nhận một map mutatedState tùy chọn được hợp nhất vào trạng thái quy trình, trừ failed.

Factory Chữ ký Mô tả
ok StepResult.ok({mutatedState}) Hoàn tất bình thường; các listener hạ nguồn được đánh giá
route StepResult.route(nextRouterKey, {mutatedState}) Hoàn tất kiểu router; chọn nhánh hạ nguồn có routeKey khớp
suspendUntilEvent StepResult.suspendUntilEvent(eventType, {mutatedState}) Tạm dừng cho đến khi một loại sự kiện miền cụ thể xảy ra
suspendUntilTasksComplete StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) Tạm dừng cho đến khi mọi tác vụ được liệt kê đạt trạng thái kết thúc
terminal StepResult.terminal({mutatedState}) Lần chạy quy trình đã kết thúc — không còn bước nào nữa
failed StepResult.failed(errorMessage) Bước thất bại kèm một thông báo lỗi

Hành vi thử lại cho body của một nút khi thất bại (PipelineNodeConfig.retryPolicy; null tắt việc thử lại).

Trường Kiểu Mô tả
maxAttempts int Tổng số lần thử kể cả lần đầu (3 = 1 lần thử + 2 lần thử lại); phải ≥ 1
backoff String linear hoặc exponential (mặc định)
initialDelayMs int Độ trễ trước lần thử lại đầu tiên, tính bằng mili giây; các độ trễ sau tăng theo backoff

Cấu hình theo từng nút được mang bên trong định nghĩa bước (packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart). Cả nút tích hợp sẵn lẫn nút tùy chỉnh đều dùng chung hình dạng này; mỗi body chỉ đọc những trường mà nó quan tâm.

Trường Kiểu Mô tả
prompt String? Mẫu prompt có thay thế {{key}}
script String? Nội dung script bash có thay thế {{key}}
agentId String? UUID của agent trong không gian làm việc sẽ được điều phối
inputKeys List<String> Các khóa trạng thái mà nút này dùng làm đầu vào
repoIds List<String> Các kho mã mà nút messaging.createSpace checkout (<repoId> hoặc <repoId>@<branch>). Rỗng = không có gì; extras['allRepos'] = mọi kho mã của không gian làm việc. Bị bỏ qua trên các bước agent.
outputKey String? Khóa trạng thái mà đầu ra của nút này được ghi vào
label String? Nhãn cho người dùng hiển thị trên canvas (mặc định là ID của bước)
outputSchema Map<String, dynamic>? JSON Schema (tập con) mà giá trị đầu ra phải thỏa mãn
reducer String? Chiến lược hợp nhất khi các nhánh song song cùng ghi vào một outputKey: append, mergeLists, mergeMaps, sum, hoặc override (mặc định)
retryPolicy StepRetryPolicy? Chính sách thử lại khi body thất bại; null = chỉ thử một lần
continueOnFail bool Khi true, một thất bại kết thúc không làm lần chạy thất bại; lỗi được cất dưới state['_stepErrors'][stepId]
timeoutMs int? Thời gian chờ theo đồng hồ thực cho body của nút, tính bằng mili giây; null = không có thời gian chờ
teamId String? Đội cần điều phối (các nút team.dispatch); loại trừ lẫn nhau với agentId
dispatchMode String? Chế độ thực thi của đội: allParallel hoặc manager
extras Map<String, dynamic> Cấu hình tự do dành riêng cho body (ví dụ iterableKey, templateId, cây điều kiện)

Các accessor dẫn xuất: spaceId (extras['spaceId'] — hội thoại đã có để làm việc trong đó), createsConversation (extras['createConversation']), conversationTitle (extras['conversationTitle']), modeName (extras['mode'] — chat / review / plan, được đọc trên nút mở phòng) và runWhen (extras['runWhen'] — bỏ qua nút khi điều kiện không được thỏa mãn).