ข้ามไปยังเนื้อหา

ไปป์ไลน์และระบบอัตโนมัติ

ไปป์ไลน์คือส่วนที่แน่นอนตายตัวของ Control Center เอเจนต์ตัดสินใจว่าจะพูดอะไร ส่วนไปป์ไลน์ตัดสินใจว่าจะเกิดอะไรต่อไป เหมือนเดิมทุกครั้ง ไปป์ไลน์คือ DAG ของขั้นตอน ที่สั่งงานเอเจนต์ รันสคริปต์ แยกสาขาตามเงื่อนไข กระจายงานไปทั่วคอลเลกชัน และส่งข้อมูล ระหว่างขั้นตอน — บันทึกไว้ต่อเนื่อง กู้รันต่อได้ และคิดต้นทุนไว้แล้ว

ไปป์ไลน์มีอยู่ด้วยเหตุผลสามข้อ: เพื่อร้อยเรียงกระบวนการหลายขั้นตอนที่ทำซ้ำ ๆ เข้าด้วยกัน เพื่อประสานเอเจนต์หลายตัวตามลำดับหรือพร้อมกัน และเพื่อตอบสนองต่อสิ่งที่เกิดขึ้นโดยไม่มี มนุษย์อยู่ตรงนั้น

เทมเพลต (PipelineDefinition) คือ DAG แบบประกาศ: ขั้นตอน อินพุตที่ประกาศไว้ และ การตั้งค่า มันอยู่ในฐานข้อมูลของเวิร์กสเปซเอง รัน (PipelineRun) คือการทำงานหนึ่งครั้ง ของเทมเพลตนั้น ซึ่งพกที่เก็บสถานะที่แก้ไขได้ ยอดรวมต้นทุนและโทเค็น และสถานะของแต่ละ ขั้นตอน

เทมเพลตหนึ่งตัวมีได้หลายรัน รันอยู่รอดข้ามการรีสตาร์ต: เอนจินโหลดรันที่กำลังทำงานอยู่ กลับมาและทำงานต่อจากจุดที่หยุดไว้

มีกลไกกันพลาดสองข้อที่จงใจทำให้ทั้งรันล้มเหลวแทนที่จะรันขั้นตอนต่อ เพราะการรันต่อจะแย่ กว่าการหยุด:

  • ขั้นตอนที่ถูก suspended นานเกิน suspendedStepTimeout (ค่าเริ่มต้น 24 ชั่วโมง) กำลังรอตั๋วงานที่จะไม่มีวันไปถึงสถานะสิ้นสุด จึงถูกทำให้ล้มเหลวเพื่อปลดรัน ข้อยกเว้นคือ extras['awaitApproval'] == true — นั่นคือเกตการอนุมัติบางส่วน orchestration.awaitApproval human.gate ไม่ได้รับข้อยกเว้น
  • ขั้นตอนที่ประกาศ extras: {'idempotent': false} และกำลังทำงานอยู่ตอนเซิร์ฟเวอร์หยุด อาจใช้ผลข้างเคียงของมันไปแล้ว (การสควอชเมิร์จ การล้าง worktree) การรันซ้ำอาจใช้ผลซ้ำ สองครั้ง เอนจินจึงทำให้มันล้มเหลวและปล่อยการลองใหม่ไว้ให้คุณตัดสินใจ

ขั้นตอนหนึ่งมีสองส่วนที่เป็นอิสระจากกัน และการแยกสองส่วนนี้ออกจากกันคือสิ่งที่ทำให้ เอนจินเล็กอยู่ได้

ชนิด (StepKind) บอกเอนจินว่า เมื่อใด ขั้นตอนจะพร้อมรันเมื่อเทียบกับขั้นตอนต้นทาง ของมัน — นั่นคือสิ่งเดียวที่ตัวจัดตารางต้องรู้ มีหกชนิด: trigger, listen, join, router, forEach และ terminal บอดี (bodyKey) คือ งาน ที่ขั้นตอนทำเมื่อถูก จัดตารางแล้ว บอดีคือคลอเชอร์ที่ลงทะเบียนไว้ตามคีย์ตอนเริ่มเซิร์ฟเวอร์ ขั้นตอนต่างชนิดกัน หลายตัวจึงใช้บอดีเดียวกันได้ เช่นขั้นตอน listen หลายตัวที่ล้วนรัน conversation.promptAgent

เพราะความหมายของการจัดตารางอยู่ในหกชนิดนี้ แค็ตตาล็อกของพฤติกรรมจึงเพิ่มขึ้นได้โดยไม่มี ใครต้องแตะตัวจัดตาราง ดูขั้นตอนไปป์ไลน์สำหรับ แค็ตตาล็อกฉบับเต็มของชนิด บอดี และการตั้งค่าของมัน

ผลสืบเนื่องสองข้อของการออกแบบแบบทะเบียนที่ควรรู้ก่อนเขียนเทมเพลตด้วยมือ:

  • ขั้นตอนที่ bodyKey ไม่ได้ลงทะเบียนไว้จะสร้าง คำเตือนตอนโหลดเทมเพลต แล้วไม่ทำงาน เลย ไม่มีอะไรล้มเหลวให้เห็นตอนรัน ขั้นตอน trigger และ terminal ได้รับยกเว้นจาก คำเตือนนั้น: ทริกเกอร์ยังรันบอดี pipeline.trigger ที่ไม่ทำอะไร เพื่อให้ตัวฟังปลายทาง ทำงาน ส่วนขั้นตอน terminal ไม่มีบอดีและเป็นเครื่องหมายเฉพาะของตัวจัดตาราง
  • คีย์ในแมป extras ของโหนดต้อง ตรงกันเป๊ะ มิฉะนั้นจะถูกละเลยโดยไม่แจ้ง มีเพียง extras['spaceId'] เท่านั้นที่วางงานของขั้นตอนเอเจนต์ลงในบทสนทนาที่มีอยู่แล้ว extras['mode'] (chat / plan / review) ถูกอ่านที่โหนดที่ เปิด ห้อง (messaging.createSpace, ค่าเริ่มต้น review) — ขั้นตอนเอเจนต์ที่ตามมาทีหลังไม่ สามารถเปลี่ยนสิทธิ์การสนทนาที่มันได้เข้าร่วมไปแล้ว การสะกดแบบอื่นของคีย์ใดคีย์หนึ่งจะ ถูกละเลย

ขั้นตอนต่าง ๆ ไม่เรียกหากันและกัน แต่ละตัวอ่านจากและเขียนลงในที่เก็บสถานะที่ใช้ร่วมกันบน รัน: ขั้นตอนอ่านอินพุตของมันตามคีย์ ทำงาน แล้วเขียนเอาต์พุตกลับไปใต้ outputKey ของตัวเอง StateReducer รวมการเขียนที่เกิดขึ้นพร้อมกันเมื่อสาขาที่รันขนานกันเขียน คีย์เดียวกัน และ TemplateRenderer แทนที่ตัวยึดตำแหน่ง {{...}} ในพรอมป์ต์และสคริปต์ จากสถานะเดียวกันนั้น

นี่คือเหตุผลที่ไปป์ไลน์ตรวจสอบย้อนหลังได้ — ที่เก็บสถานะคือเรื่องราวทั้งหมดของรัน

แถว PipelineTrigger ประกาศว่าเทมเพลตเริ่มเองเมื่อใด มีสี่ชนิด:

ทริกเกอร์ เริ่มรันเมื่อ
เหตุการณ์โดเมน เกิดเหตุการณ์โดเมนที่ตรงกัน เช่น PullRequestPublished หรือ TicketAssigned
ตารางเวลา นิพจน์ cron/ช่วงเวลาถึงกำหนด
ด้วยตนเอง คุณรันด้วยมือ การมีทริกเกอร์แบบด้วยตนเองที่เปิดใช้นั้นคือสิ่งที่ทำให้เทมเพลตปรากฏในตัวเลือกการรัน
Webhook ระบบภายนอกส่ง POST ไปที่ /webhooks/<token> บนพอร์ต HTTP ของเซิร์ฟเวอร์

ทริกเกอร์แบบเหตุการณ์เป็นชุดปิดตายตัว: มี 16 ชนิดเหตุการณ์ที่ตัวกระจายรู้จักและแสดงใน ตัวเลือก (EventPayloadMapper.knownEventTypes) และไม่มีอย่างอื่นเริ่มไปป์ไลน์ได้ ใน 16 ชนิดนั้นมี 14 ชนิดที่มีการแมปเพย์โหลด อีกสองชนิด — TicketCreated และ TicketStatusChanged — ไม่มีการแมป ดังนั้นทริกเกอร์บนสองชนิดนี้จะเปิดอยู่แต่ไม่เคย ทำงาน ดูเหตุการณ์โดเมนสำหรับรายการฉบับเต็ม

โทเค็น webhook ทำหน้าที่เป็นซีเคร็ต HMAC ไปด้วย: เฮดเดอร์ X-Hub-Signature-256: sha256=<hex> ของคำขอจะถูกตรวจสอบกับ HMAC-SHA256(body, token) การส่งที่ไม่ผ่านการตรวจสอบจะถูกปฏิเสธและเล่นซ้ำไม่ได้ ส่วนรายการซ้ำจะถูกตัดออกด้วย dedupe_key เพราะแถวทริกเกอร์ไม่ซ้ำกันเมื่อเทียบ (เวิร์กสเปซ, ชนิดเหตุการณ์, เทมเพลต) เทมเพลตหนึ่งตัวจึงมีทริกเกอร์ webhook ได้ไม่เกิน หนึ่งตัว และมีทริกเกอร์ได้ไม่เกินหนึ่งตัวต่อหนึ่งชนิดเหตุการณ์โดเมน

เทมเพลตในตัวติดตั้ง ทริกเกอร์แบบด้วยตนเองและแบบเหตุการณ์ให้เปิดไว้ ส่วน ทริกเกอร์ตามตารางเวลาติดตั้งมาแบบปิด งานกวาดซ้ำตามรอบจึงต้องเปิดเองเสมอ

เทมเพลตไปป์ไลน์สิบสามตัวถูกติดตั้งไว้ในทุกเวิร์กสเปซ และ แปดตัวมาพร้อมสถานะปิด: external_pr_welcome, cross_review, ticket_to_pr, pr_triage, pre_merge_gate, release_notes, dep_audit และ pr_digest

นี่คือส่วนที่ทำให้คนแปลกใจ ทริกเกอร์ของเทมเพลตเหล่านี้ติดตั้งมาแบบ เปิด แต่ PipelineEngine.start ปฏิเสธเทมเพลตที่ปิดอยู่และคืนค่า null — ทริกเกอร์จึงทำงานไป อย่างไร้ผลและไม่มีรันปรากฏขึ้น สวิตช์อยู่ที่เทมเพลต ไม่ใช่ที่ทริกเกอร์ เปิดใช้งานที่ การตั้งค่า → เวิร์กสเปซ → เทมเพลตไปป์ไลน์ ก่อนจะคาดหวังให้แปดตัวนั้นทำอะไรได้

การติดตั้งซ้ำในเวิร์กสเปซจะเก็บสิ่งที่คุณเลือกไว้: การตั้งค่า isEnabled และแถวทริกเกอร์ ที่มีอยู่ของคุณจะคงอยู่ มีข้อยกเว้นโดยเจตนาอยู่หนึ่งข้อพอดี — ตารางเวลารายวันของ pr_merged_cleanup จะถูกบังคับให้เปิด แม้ก่อนหน้านี้จะปิดอยู่ เพราะมันคือการเก็บขยะ หากไม่มีมัน แถว worktree พาร์ทิชันของกราฟโค้ด และสำเนาแบบ copy-on-write จะพอกพูนขึ้น และนั่นไม่เคยตั้งใจให้เป็นทางเลือกของผู้ใช้

ความไม่สมมาตรอีกข้อที่ควรรู้: เทมเพลตในตัว pr_review จงใจไม่โพสต์ขึ้น GitHub อีกต่อไป การเผยแพร่รีวิวเป็นขั้นตอนแยกต่างหากที่ผู้ใช้ต้องอนุมัติเอง และไปป์ไลน์ที่โพสต์โดยตรงจะ เผยแพร่ซ้ำสองครั้ง แต่ cross_review, ticket_to_pr และ pr_triage ยังคงโพสต์ ความคิดเห็นตรงขึ้นไปยัง GitHub เมื่อทำงาน

PipelineEngine สร้างบันทึกรัน จัดตารางโหนดเริ่มต้นที่ตรงกับชนิดเหตุการณ์ของรัน แล้วไล่ ไปตาม DAG: เมื่อขั้นตอนต่าง ๆ เสร็จ มันจะประเมินทริกเกอร์ปลายทาง แก้สาขาของ router รอ join ปรับใช้นโยบายลองใหม่และ continue-on-fail และบันทึกสถานะ ต้นทุน และข้อผิดพลาดไว้ ทุกขั้นตอน เส้นเชื่อมที่ออกจากจุดเริ่มต้นอีกจุดจะถูกละเลยสำหรับรันนั้น การทำงานจาก ตารางเวลาจึงไม่ต้องรอเงื่อนไขที่เป็นแบบด้วยตนเองเท่านั้น

สิ่งที่มัน ไม่ รู้คือเรื่องใด ๆ เกี่ยวกับระบบตั๋วงาน การสั่งงาน GitHub หรือการรับส่ง ข้อความ รอยต่อขยายเพียงจุดเดียวของมันคือ PipelineBodyRegistry บอดีที่ลงทะเบียนที่นั่น คือสิ่งที่ถือ AgentDispatchPort, MessagingPort และพอร์ตอื่นในตระกูลเดียวกัน — นี่คือเหตุผลที่การเพิ่มความสามารถให้ไปป์ไลน์ไม่เคยต้องแก้ตัวจัดตาราง

ขั้นตอนที่ล้มเหลวจะบันทึกข้อความข้อผิดพลาดของมันแล้วเปลี่ยนไปเป็น failed หากขั้นตอนนั้น ประกาศ continueOnFail ขั้นตอนปลายทางจะดำเนินต่อไปและข้อผิดพลาดจะถูกพักไว้ในสถานะของ รัน มิฉะนั้นรันจะล้มเหลว ขั้นตอนที่มี StepRetryPolicy จะถูกลองใหม่ก่อน ด้วยการหน่วง แบบเชิงเส้นหรือแบบเอกซ์โพเนนเชียล ก่อนที่สองกรณีข้างต้นจะบังคับใช้