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

Quy trình và tự động hóa

Quy trình là nửa tất định của Control Center. Agent quyết định nói gì; quy trình quyết định điều gì xảy ra tiếp theo, và luôn giống hệt nhau ở mọi lần. Một quy trình là một DAG gồm các bước có thể điều phối agent, chạy script, rẽ nhánh theo điều kiện, tỏa ra trên một tập hợp và truyền dữ liệu giữa các bước — được lưu bền, chạy tiếp được và có tính chi phí.

Chúng tồn tại vì ba lý do: để nối chuỗi một quy trình nhiều bước lặp đi lặp lại, để phối hợp nhiều agent theo trình tự hoặc song song, và để phản ứng với một việc gì đó đã xảy ra mà không cần con người có mặt.

Một mẫu (PipelineDefinition) là DAG khai báo: các bước, đầu vào được khai báo và cấu hình. Nó sống trong cơ sở dữ liệu của chính không gian làm việc. Một lần chạy (PipelineRun) là một lần thực thi mẫu đó, mang theo một túi trạng thái có thể thay đổi, tổng chi phí và token cùng trạng thái của từng bước.

Một mẫu có nhiều lần chạy. Lần chạy sống sót qua khởi động lại: engine nạp lại những lần chạy đang dang dở và tiếp tục từ chỗ chúng đã dừng.

Hai chốt an toàn cố ý đánh dấu thất bại cả lần chạy thay vì chạy tiếp một bước, bởi chạy tiếp sẽ còn tệ hơn là dừng lại:

  • Một bước đã suspended lâu hơn suspendedStepTimeout (mặc định 24 giờ) là đang chờ những phiếu sẽ không bao giờ tới trạng thái kết thúc, nên nó bị đánh dấu thất bại để giải phóng lần chạy. Ngoại lệ là extras['awaitApproval'] == true — đó là cổng phê duyệt một phần orchestration.awaitApproval. human.gate không được miễn.
  • Một bước khai báo extras: {'idempotent': false} đang chạy dở khi máy chủ dừng có thể đã áp dụng hiệu ứng phụ của nó rồi (một squash merge, một lần dọn dẹp worktree). Chạy lại có thể áp dụng hai lần, nên engine đánh dấu bước đó thất bại và để bạn tự thử lại.

Một bước có hai phần độc lập nhau, và việc tách bạch chúng chính là điều giúp engine luôn nhỏ gọn.

kind (StepKind) cho engine biết khi nào một bước trở nên có thể chạy tương đối với các bước thượng nguồn — đó là điều duy nhất bộ lập lịch cần biết. Có sáu kind: trigger, listen, join, router, forEach và terminal. body (bodyKey) là công việc bước đó thực hiện sau khi được lập lịch. Body là các closure được đăng ký theo khóa lúc máy chủ khởi động, nên nhiều bước thuộc các kind khác nhau có thể dùng chung một body: chẳng hạn vài bước listen cùng chạy conversation.promptAgent.

Vì ngữ nghĩa lập lịch nằm trong sáu kind, danh mục hành vi có thể lớn lên mà không ai phải đụng tới bộ lập lịch. Xem Loại bước quy trình để có danh mục đầy đủ về các kind, body và cấu hình của chúng.

Hai hệ quả của thiết kế registry đáng để biết trước khi bạn tự tay viết một mẫu:

  • Một bước có bodyKey không được đăng ký sẽ tạo ra cảnh báo lúc nạp mẫu rồi sau đó không bao giờ thực thi. Không có gì hỏng ầm ĩ lúc chạy. 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ác listener hạ nguồn kích hoạt; một bước terminal không có body và đóng vai trò điểm đánh dấu cho bộ lập lịch.
  • Các khóa trong map extras của một node là khớp chính xác, và mọi trường hợp khác đều bị âm thầm bỏ qua. Chỉ extras['spaceId'] mới đặt công việc của một bước agent vào một hội thoại đã có. extras['mode'] (chat / plan / review) được đọc trên node mở phòng (messaging.createSpace, mặc định review) — một bước agent về sau không thể cấp lại quyền cho một hội thoại mà nó đã tham gia. Mọi cách viết khác của hai khóa này đều bị bỏ qua.

Các bước không gọi nhau. Chúng đọc từ và ghi vào một túi trạng thái chung của lần chạy: một bước đọc đầu vào theo khóa, thực thi rồi ghi đầu ra trở lại dưới outputKey của chính nó. StateReducer hợp nhất các ghi đồng thời khi những nhánh song song cùng nhắm vào một khóa, và TemplateRenderer thay thế các placeholder {{...}} trong prompt và script từ chính trạng thái đó.

Đây là lý do một quy trình vẫn soi lại được sau khi đã chạy — túi trạng thái là toàn bộ câu chuyện của lần chạy.

Các hàng PipelineTrigger khai báo khi nào một mẫu tự khởi động. Có bốn loại:

Trình kích hoạt Khởi chạy một lần chạy khi
Sự kiện miền Một sự kiện miền khớp xảy ra — ví dụ PullRequestPublished hoặc TicketAssigned
Theo lịch Một biểu thức cron/khoảng thời gian tới hạn
Chạy thủ công Bạn tự chạy bằng tay; sự hiện diện của một trình kích hoạt thủ công đang bật là thứ đưa mẫu vào trình chọn lần chạy
Webhook Một hệ thống bên ngoài POST tới /webhooks/<token> trên cổng HTTP của máy chủ

Các trình kích hoạt theo sự kiện là một tập đóng: dispatcher biết 16 loại sự kiện và đưa chúng ra trong trình chọn (EventPayloadMapper.knownEventTypes), không gì khác có thể khởi chạy một quy trình. Mười bốn trong số 16 loại đó có ánh xạ payload. Hai loại — TicketCreated và TicketStatusChanged — không có, nên một trình kích hoạt trên một trong hai loại đó cứ ở trạng thái bật mà không bao giờ kích hoạt. Xem Sự kiện miền để có danh sách đầy đủ.

Token webhook đồng thời là khóa HMAC: header X-Hub-Signature-256: sha256=<hex> của request được xác minh dựa trên HMAC-SHA256(body, token), những gói tin không xác minh được sẽ bị từ chối và không thể phát lại, còn các bản trùng lặp bị loại bỏ bằng dedupe_key. Vì các hàng trình kích hoạt là duy nhất theo (không gian làm việc, loại sự kiện, mẫu), một mẫu chỉ có thể có tối đa một trình kích hoạt webhook và một trình kích hoạt cho mỗi loại sự kiện miền.

Các mẫu tích hợp sẵn gieo trình kích hoạt thủ công và theo sự kiện ở trạng thái bật; trình kích hoạt theo lịch được gieo ở trạng thái tắt, nên một lượt quét định kỳ luôn phải được chủ động bật.

Những mẫu xuất xưởng ở trạng thái tắt

Phần tiêu đề “Những mẫu xuất xưởng ở trạng thái tắt”

Mười ba mẫu quy trình được gieo vào mọi không gian làm việc và tám trong số đó xuất xưởng ở trạng thái tắt: external_pr_welcome, cross_review, ticket_to_pr, pr_triage, pre_merge_gate, release_notes, dep_audit và pr_digest.

Đây chính là phần khiến người ta bất ngờ. Trình kích hoạt của chúng được gieo đang bật, nhưng PipelineEngine.start từ chối một mẫu bị tắt và trả về null — thế nên trình kích hoạt kích hoạt vào khoảng không và không có lần chạy nào xuất hiện. Mẫu mới là công tắc, chứ không phải trình kích hoạt. Hãy bật mẫu tại Cài đặt → Không gian làm việc → Mẫu quy trình trước khi kỳ vọng bất kỳ mẫu nào trong tám mẫu đó làm được gì.

Gieo lại một không gian làm việc giữ nguyên mọi thứ bạn đã chọn: thiết lập isEnabled và các hàng trình kích hoạt hiện có của bạn vẫn còn. Có đúng một ngoại lệ cố ý — lịch chạy hằng ngày của pr_merged_cleanup bị buộc bật kể cả khi trước đó đã tắt, bởi đó là việc thu gom rác. Các hàng worktree, phân vùng đồ thị mã và bản sao copy-on-write sẽ tích tụ nếu thiếu nó, và điều đó chưa bao giờ được xem là lựa chọn của người dùng.

Một điểm bất đối xứng nữa đáng biết: mẫu tích hợp sẵn pr_review cố ý không còn đăng lên GitHub. Xuất bản một đánh giá là một bước riêng, có cổng cho người dùng duyệt, và một quy trình đăng trực tiếp sẽ xuất bản hai lần. cross_review, ticket_to_pr và pr_triage thì vẫn đăng thẳng một bình luận lên GitHub khi chúng chạy.

PipelineEngine tạo bản ghi lần chạy, lập lịch node khởi đầu khớp với loại sự kiện của lần chạy, rồi duyệt qua DAG: khi các bước hoàn tất, nó đánh giá các trình kích hoạt hạ nguồn, giải các nhánh router, chờ các điểm join, áp dụng chính sách thử lại và continue-on-fail, đồng thời lưu bền trạng thái, chi phí và lỗi ở mỗi bước. Những cạnh xuất phát từ một điểm khởi đầu khác bị bỏ qua trong lần chạy đó, nên một lần kích hoạt theo lịch không chờ vào một điều kiện chỉ dành cho chạy thủ công.

Điều nó không biết là bất cứ thứ gì về phiếu, điều phối, GitHub hay nhắn tin. Đường nối mở rộng duy nhất của nó là PipelineBodyRegistry. Chính những body đăng ký ở đó nắm giữ AgentDispatchPort, MessagingPort và các anh em của chúng — vì thế thêm một năng lực cho quy trình không bao giờ đồng nghĩa với việc phải sửa bộ lập lịch.

Một bước thất bại ghi lại thông báo lỗi của nó rồi chuyển sang failed. Nếu bước đó khai báo continueOnFail, các bước hạ nguồn vẫn tiếp tục và lỗi được cất vào trạng thái lần chạy; nếu không, cả lần chạy thất bại. Một bước có StepRetryPolicy được thử lại trước, với backoff tuyến tính hoặc lũy thừa, trước khi một trong hai điều trên được áp dụng.