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

ขั้นตอนไปป์ไลน์

ขั้นตอนไปป์ไลน์หนึ่งขั้นมีสองแกนที่เป็นอิสระจากกัน:

  • ชนิด (StepKind) — เอนจิน จัดตาราง ขั้นตอนสัมพันธ์กับทริกเกอร์ของมันอย่างไร
  • คีย์บอดี (BuiltInBodyKeys) — คลอเชอร์บอดีที่ลงทะเบียนไว้ตัวใดที่ ลงมือทำงาน ของขั้นตอน

นิยามไว้ใน packages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart

ชนิด ความหมายของการจัดตาราง
trigger จุดเริ่มต้นบังคับ — มีหนึ่งตัวพอดีต่อเทมเพลต และเป็นโหนดแรกเสมอ ตัวมันเองไม่ทำงานใด ๆ สิ่งที่ทำให้รันเริ่มขึ้น (ด้วยตนเอง / เหตุการณ์ / ตารางเวลา) ถูกติดตามแยกต่างหากเป็นแถว PipelineTrigger บอดีของมันคือ pipeline.trigger ที่ไม่ทำอะไร
listen ทำงานเมื่อขั้นตอนต้นทางทั้งหมด (ใน StepTrigger.sourceStepIds) เสร็จสิ้น
join ทำงานเมื่อขั้นตอนทั้งหมดใน waitForStepIds ไปถึงสถานะสิ้นสุด
router การแยกสาขาตามเงื่อนไข — บอดีคืนค่า StepResult.route(key) ซึ่งจะทำให้เฉพาะเส้นเชื่อมปลายทางที่ routeKey ตรงกันทำงาน ส่วนสาขาที่ไม่ได้เลือกจะถูกทำเครื่องหมายว่าข้าม
forEach ถูกจัดตารางเหมือน listen (ทำงานเมื่อ sourceStepIds ทั้งหมดเสร็จสิ้น) บอดี flow.forEach ที่ลงทะเบียนไว้คือตัวที่วนซ้ำ เอนจินไม่ได้สร้างขั้นตอนลูกหนึ่งตัวต่อหนึ่งรายการ
terminal เครื่องหมายเฉพาะของตัวจัดตารางที่ไม่มีบอดี รันของไปป์ไลน์จะเสร็จสิ้นเมื่อขั้นตอน terminal ทำงานเสร็จ

คลอเชอร์บอดีที่ลงทะเบียนไว้โดยใช้ค่าคงที่ใน BuiltInBodyKeys (packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart) เป็นคีย์ มีทั้งหมด 25 ตัว ระบุไว้ทั้งหมดด้านล่าง การตั้งค่าจะอ่านจาก PipelineNodeConfig ของขั้นตอน (ดูด้านล่าง) เว้นแต่ระบุไว้เป็นอย่างอื่น ส่วน “คีย์สถานะ” จะอ่านจากสถานะของไปป์ไลน์ / เพย์โหลดของทริกเกอร์ตอนลงมือทำงาน

ขั้นตอนที่ bodyKey ไม่ได้ลงทะเบียนไว้จะสร้างคำเตือนตอนโหลดเทมเพลต แล้วไม่ทำงานเลย — มันไม่ได้ทำให้รันล้มเหลว ขั้นตอน trigger และ terminal ได้รับยกเว้นจากคำเตือนนั้น: ทริกเกอร์ยังรันบอดี pipeline.trigger ที่ไม่ทำอะไร ส่วนขั้นตอน terminal ไม่มีบอดี

บอดีที่ไม่ทำอะไรของโหนด trigger ที่บังคับ — เสร็จสิ้นทันทีเพื่อให้เอนจินกระจายต่อไปยังตัวฟังปลายทาง ไม่มีการตั้งค่า

ขั้นตอนเชลล์ที่ไม่มีเอเจนต์ (bash -c) ตัวยึดตำแหน่ง {{key}} ในสคริปต์จะถูกแทนที่จากสถานะและเพย์โหลดของทริกเกอร์ ด้วยค่าที่ escape อักขระพิเศษไว้แล้วสำหรับเชลล์

เขตข้อมูลการตั้งค่า คำอธิบาย
script คำสั่งเชลล์ที่จะรัน (จำเป็น)
outputKey คีย์สถานะที่รับ stdout ที่ตัดช่องว่างหัวท้ายแล้วเมื่อออกด้วยรหัส 0

รันโดยมี cwd เป็น <cc_root>/pipelines/<pipelineRunId>/ (ใช้ร่วมกันโดยขั้นตอน bash ทั้งหมดในรันเดียว) และมี GITHUB_TOKEN ในสภาพแวดล้อม ยังเขียน <stepId>_runDir ลงในสถานะด้วย การออกด้วยรหัสที่ไม่ใช่ศูนย์ทำให้ขั้นตอนล้มเหลว พร้อมส่วนท้ายของ stderr

โหนดพรอมป์ต์และสั่งงานแบบทั่วไป: เรนเดอร์พรอมป์ต์ สั่งงานเอเจนต์เข้าสู่บทสนทนา แล้วระงับจนกว่ารันจะเสร็จสิ้น เพย์โหลด submit_output ของเอเจนต์จะถูกเก็บเข้าสู่สถานะใต้ outputKey

เขตข้อมูลการตั้งค่า คำอธิบาย
agentId UUID ของเอเจนต์ที่ผูกกับเวิร์กสเปซที่จะสั่งงาน (จำเป็น)
prompt ข้อความคำสั่ง รองรับการแทนที่ {{key}} (จำเป็น)
outputKey คีย์สถานะสำหรับเอาต์พุตที่เก็บมาได้
outputSchema JSON Schema ที่เอาต์พุตต้องเป็นไปตามนั้น
label ป้ายชื่อที่มนุษย์อ่านที่แสดงบนแคนวาส
extras.spaceId บทสนทนาที่มีอยู่แล้วที่จะทำงานในนั้น (ค่าเริ่มต้น: บทสนทนาที่ซ่อนอยู่)
extras.conversationTitle สตรีมที่มีชื่อภายในสเปซนั้น (ไม่บังคับ)
extras.mode อ่านที่โหนดที่ เปิด ห้อง (messaging.createSpace) ไม่ใช่ที่นี่ ค่าเริ่มต้น review

บอดีของ router — อ่าน config.extras ประเมินเงื่อนไข แล้วคืนค่า StepResult.route(key) เงื่อนไข ไม่ใช่ นิพจน์ JavaScript มีรูปแบบการเขียนอยู่สามแบบ รองรับตามลำดับความสำคัญ:

  • ทรีเพรดิเคต (extras.predicate) — ทรีบูลีนที่เลือกเส้นทาง "true" / "false" แต่ละโหนดเป็นแมปที่มี type:
    • {"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false} — เป็นจริงเมื่อมีพาธใด ๆ ที่ระบุอยู่บนดิสก์; negate กลับค่าเป็นตรงข้าม; recursive ค้นหาในไดเรกทอรีย่อยด้วย (ข้าม .git, node_modules, build, .dart_tool) พาธแบบสัมพัทธ์จะถูกตีความโดยอิงกับ state[baseKey] (ค่าเริ่มต้น repo_local_path) มิฉะนั้นอิงกับไดเรกทอรีเวิร์กสเปซของแต่ละรัน
    • {"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80} — ตัวดำเนินการ equals, notEquals, contains, exists, notExists, gt, lt; อ่านสถานะของไปป์ไลน์ ไม่ใช่ระบบไฟล์
    • {"type": "and" | "or", "of": [<predicate>, ...]} — กลุ่มบูลีน
    • {"type": "not", "of": <predicate>} — การนิเสธ
  • สวิตช์ (extras.switchKey) — {"switchKey": "pr_class", "cases": [...], "default": "standard"}; เลือกเส้นทางไปยังเคสแรกที่ค่าสถานะมีอยู่โดยไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ มิฉะนั้นใช้ default
  • การเปรียบเทียบ (ระดับบนสุดแบบเดิม extras.left / extras.op / extras.right) — เทียบเท่าเพรดิเคต comparison เก็บไว้สำหรับเทมเพลตที่เขียนไว้ก่อนมีทรี

เส้นเชื่อมที่ออกจากโหนดมี routeKey ซึ่งต้องตรงกับคีย์ที่คืนมา

โพสต์ข้อค้นพบที่รวบรวมแล้วเป็นความคิดเห็นรีวิว PR ผ่านไคลเอนต์ PR ของ GitHub

คีย์สถานะ คำอธิบาย
repo_full_name owner/repo (จำเป็น)
pr_number หมายเลข PR — int หรือสตริงตัวเลข (จำเป็น)
consolidated_findings เนื้อความของความคิดเห็น (จำเป็น)

คืนค่า StepResult.terminal โดยมี comment_review_id และ commented_at อยู่ในสถานะ

โพสต์ข้อความไปยังสเปซข้อความผ่าน MessagingPort

คีย์สถานะ คำอธิบาย
space_id สเปซเป้าหมาย (จำเป็น)
content เนื้อความของข้อความ อ่านจากสถานะตามตัวอักษร (จำเป็น)

เขียน posted_space_id และ posted_at ลงในสถานะ

สั่งงานทั้งทีมแทนเอเจนต์ตัวเดียว แล้วระงับจนกว่ารันของสมาชิกจะเสร็จสิ้น

เขตข้อมูลการตั้งค่า คำอธิบาย
teamId ทีมที่ผูกกับเวิร์กสเปซที่จะสั่งงาน (จำเป็น; ใช้ร่วมกับ agentId ไม่ได้)
prompt ข้อความเป้าหมาย รองรับการแทนที่ {{key}} (จำเป็น)
dispatchMode allParallel (ค่าเริ่มต้น — หนึ่งงานต่อสมาชิกหนึ่งคน) หรือ manager (สั่งงานเฉพาะหัวหน้าเพื่อประสานงาน)
outputKey คีย์สถานะสำหรับเอาต์พุตของสมาชิกที่เก็บมาได้
outputSchema, label, extras.spaceId เช่นเดียวกับ conversation.promptAgent

เกตการอนุมัติ สั่งงานเอเจนต์ผู้อนุมัติเข้าสู่บทสนทนา (โหมดรีวิว) ด้วยพรอมป์ต์ของเกตและสัญญาเอาต์พุต {decision, reason} แล้วระงับจนกว่าผู้อนุมัติจะส่งผ่าน submit_output

เขตข้อมูลการตั้งค่า คำอธิบาย
agentId เอเจนต์ผู้อนุมัติ (จำเป็น)
prompt พรอมป์ต์ของเกต (ไม่บังคับ; ใช้ค่าเริ่มต้นเมื่อไม่ได้ระบุ)
outputKey คีย์สถานะสำหรับเพย์โหลด {decision, reason} ที่เก็บมาได้
outputSchema มีค่าเริ่มต้นเป็นสคีมาการอนุมัติ (decision: approved / rejected, reason)
label, extras.spaceId เช่นเดียวกับ conversation.promptAgent

เกตจะดำเนินต่อไปได้ผ่าน submit_output เท่านั้น BuiltInBodyKeys.humanGate ไลบรารีชนิดโหนด และข้อความพรอมป์ต์ของเทมเพลตในตัวตัวหนึ่ง ต่างก็อ้างถึงเครื่องมือ MCP ชื่อ approve_step และ reject_step; ไม่มีเครื่องมือทั้งสองตัวอยู่จริง ในแพ็กเกจหรือรีจิสทรีใด ๆ

ลบ worktree แยกส่วนที่ตกค้าง เลือกโหมดของมันจากเพย์โหลดของทริกเกอร์ เคารพแฟล็ก dryRun ของรัน

คีย์สถานะ คำอธิบาย
ticket_id ปล่อย worktree ของตั๋วงานนั้น
repo_full_name + pr_number ปล่อย worktree ของตัวแก้ไข PR ที่เป็นชั่วคราว
space_id รื้อ worktree และโฟลเดอร์ของการสนทนานั้น
(ไม่มีข้อใดข้างต้น) กวาดเวิร์กสเปซ: ไดเรกทอรีที่หายไป สเปซที่ตายแล้ว โฟลเดอร์การสนทนาที่ไม่มีเจ้าของ

outputKey (ไม่บังคับ) จะได้รับสตริงสรุป

การแมป / กระจายงานเหนือคอลเลกชันในสถานะ: เรนเดอร์พรอมป์ต์หนึ่งครั้งต่อหนึ่งรายการ แล้วสั่งงานเอเจนต์ หนึ่งครั้ง ด้วยพรอมป์ต์เหล่านั้นที่ต่อกัน (คั่นด้วย ---) และระงับจนกว่ารันนั้นจะเสร็จสิ้น คอลเลกชันว่างจะเสร็จสิ้นทันทีพร้อมรายการว่าง ไม่ใช่การสั่งงานแบบขนานหนึ่งครั้งต่อหนึ่งรายการ

เขตข้อมูลการตั้งค่า คำอธิบาย
agentId เอเจนต์ที่จะสั่งงานต่อหนึ่งรายการ (จำเป็น)
prompt พรอมป์ต์ต่อหนึ่งรายการ รองรับการแทนที่ {{key}} (จำเป็น)
extras.iterableKey คีย์สถานะที่เก็บคอลเลกชัน (จำเป็น)
extras.itemKey คีย์ที่รายการปัจจุบันถูกผูกไว้ในพรอมป์ต์ (ค่าเริ่มต้น item)
outputKey คีย์สถานะสำหรับเอาต์พุตที่เก็บมาได้ (หนึ่งการสั่งงาน ไม่ใช่รายการ)

รันเทมเพลตไปป์ไลน์อื่นเป็นขั้นตอนย่อยที่ซ้อนอยู่ (ไปป์ไลน์ย่อยจะรันเป็นรันลูกโดยตั้งค่า parentPipelineRunId ไว้) ขั้นตอนจะระงับจนกว่ารันลูกจะไปถึงสถานะสิ้นสุด จากนั้นสถานะสุดท้ายของรันลูกจะถูกผสานไว้ใต้ outputKey

เขตข้อมูลการตั้งค่า คำอธิบาย
extras.templateId เทมเพลตลูกที่จะรัน (จำเป็น; ไปป์ไลน์เรียกตัวเองไม่ได้)
inputKeys คีย์สถานะที่คัดลอกเข้าไปในเพย์โหลดของทริกเกอร์ของรันลูก
outputKey คีย์สถานะสำหรับสถานะสุดท้ายที่ผสานแล้วของรันลูก

การทำดัชนีด้วย tree-sitter แบบเบื้องหลัง: เดินไปทั่วรีโป แยกสัญลักษณ์/เส้นเชื่อมในไอโซเลตของวอร์กเกอร์ แล้วนำเข้าสู่กราฟโค้ดของเวิร์กสเปซ สตรีมความคืบหน้าเข้าไปในแถวของรันขั้นตอน; รองรับ dry-run tree-sitter และไวยากรณ์ของมันเป็นเนทีฟที่จำเป็น — dylib ที่หายไปหมายความว่าเซิร์ฟเวอร์ไม่เคยบูตขึ้น และไวยากรณ์ที่ resolve ไม่สำเร็จกลางรันจะทำให้ขั้นตอนล้มเหลวแทนที่จะข้ามไป

คีย์สถานะ คำอธิบาย
repo_id รีโปที่จะทำดัชนี (จำเป็น)
repo_local_path พาธในเครื่องของเช็กเอาต์ (จำเป็น)

การแยกผู้พูดแบบออฟไลน์ อ่านเสียงที่เก็บไว้ของการประชุม จัดกลุ่มเป็นผู้พูด (Person 1, Person 2, …) ติดป้ายกำกับใหม่ให้กับส่วนต่าง ๆ ของบันทึกถอดเสียง และเขียนทับสถานะ transcript; ยังปล่อย diarization_spans สำหรับขั้นตอน meeting.updateTranscript ที่รันขนานกันด้วย ส่งต่อบันทึกถอดเสียงไปโดยไม่เปลี่ยนแปลงเมื่อไม่มีเสียงที่ถูกเก็บไว้ หรือยังไม่ได้ติดตั้งโมเดล

คีย์สถานะ คำอธิบาย
meeting_id การประชุมที่จะแยกผู้พูด (จำเป็น)

บอดีที่บันทึกสรุปการประชุมแบบดีเทอร์มินิสติก แต่ละตัวอ่าน meeting_id และเพย์โหลด meeting_outcome แบบมีโครงสร้างของขั้นตอนเอเจนต์ ({summary, enhancedNotes, actionItems[], decisions[]}) จากสถานะ แล้วเขียนส่วนของตัวเองลงตารางของตัวเอง — บันทึก รายการงานที่ต้องทำ หรือการตัดสินใจ แถวที่บันทึกไว้ก่อนหน้าจะไม่ถูกล้างทิ้งเมื่อรันทำงานแบบลดระดับ

คีย์บอดี คำอธิบาย
meeting.identifySpeakers การรู้จำผู้พูดข้ามการประชุม: จับคู่ผู้พูดที่แยกได้กับโปรไฟล์เสียงที่บันทึกไว้ และนำการจับคู่ที่มั่นใจไปใช้โดยอัตโนมัติ ไม่ทำอะไรเมื่อไม่มีโปรไฟล์/เอ็มเบดดิง
meeting.updateTranscript นำป้ายกำกับ Person N จาก diarization_spans ไปใช้ และผสานชิ้นส่วนรายหน้าต่างเป็นช่วงคำพูดรายผู้พูด จากนั้นบันทึกบันทึกถอดเสียงที่ทำความสะอาดแล้ว ไม่ทำอะไรเมื่อการแยกผู้พูดไม่ให้ผลลัพธ์ใด ๆ
meeting.assemblePlayback ประกอบแทร็กเล่นกลับแบบผสมของการประชุมจากไฟล์ WAV รายช่องสัญญาณที่เก็บไว้ ไม่ทำอะไรเมื่อไม่มีเสียงที่ถูกเก็บไว้
orchestration.markPhase เมื่อสิ้นสุด DAG ของงาน เขียนสัญญาณความล้มเหลวให้กับตั๋วงานย่อยที่ไม่มีเอาต์พุต แล้วเปลี่ยนสถานะการประสานงานเป็น synthesizing
orchestration.persistDeliverable เขียนเอาต์พุตของการสังเคราะห์ลงในตั๋วงานแม่ ทำตั๋วงานนั้นให้เสร็จสิ้น โพสต์สิ่งที่ส่งมอบ แล้วทำเครื่องหมายการประสานงานเป็น completed
orchestration.awaitApproval เกตการอนุมัติบางส่วน: เสร็จสิ้นทันทีเมื่อคีย์โหนดของขั้นตอนอยู่ในชุดที่อนุมัติแล้วของการประสานงาน มิฉะนั้นจะระงับจนกว่าการอนุมัติในภายหลังจะทำให้กลับมาทำงานต่อ นี่เป็นบอดีเดียวที่ตั้งค่า extras.awaitApproval ซึ่งยกเว้นมันจากหมดเวลา 24 ชั่วโมงของขั้นตอนที่ถูกระงับ
messaging.createSpace เปิดบทสนทนาที่ส่วนที่เหลือของเทมเพลตทำงานอยู่ในนั้น เผยแพร่ไว้ใต้ outputKey ของขั้นตอน (เทมเพลตในตัวใช้ pipeline_space_id) รายการ repoIds ที่ว่างเปล่าจะไม่เช็กเอาต์อะไรเลย; extras['allRepos'] จะเช็กเอาต์ทุกรีโปในเวิร์กสเปซ extras['createConversation'] (ปิดไว้เป็นค่าเริ่มต้น) จะเปิดสตรีมที่มีชื่อด้วย ขั้นตอนเอเจนต์จะเข้าร่วมห้องและไม่เคยเปิดห้องเอง ดังนั้นการกระจายงานที่ไม่มีโหนดนี้จะล้มเหลวตอนสั่งงาน — และการต่อมันไว้ครั้งเดียวหมายความว่าการกระจายงานทั้งชุดใช้เช็กเอาต์ร่วมกันหนึ่งชุด แทนที่จะจัดเตรียมให้ทีละอัน
prReview.finalize ขั้นตอนสุดท้ายของเทมเพลตรีวิว PR: จัดเรียงโหนดรีวิวที่สะสมไว้ลงในถังฉันทามติ แล้วคำนวณคำตัดสินต่อหนึ่ง PR
skills.analyze รันการสแกนซัพพลายเชนของสกิลบนสกิลที่ติดตั้งไว้ในเวิร์กสเปซ และบันทึกคำตัดสินของแต่ละรายการ

บอดีของขั้นตอนคืนค่า StepResult (packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart) factory ทั้งหมดรับแมป mutatedState แบบไม่บังคับที่ผสานเข้าสู่สถานะของไปป์ไลน์ ยกเว้น failed

factory ลายเซ็น คำอธิบาย
ok StepResult.ok({mutatedState}) เสร็จสิ้นตามปกติ; ตัวฟังปลายทางจะถูกประเมิน
route StepResult.route(nextRouterKey, {mutatedState}) เสร็จสิ้นของ router; เลือกสาขาปลายทางที่ routeKey ตรงกัน
suspendUntilEvent StepResult.suspendUntilEvent(eventType, {mutatedState}) หยุดชั่วคราวจนกว่าเหตุการณ์โดเมนชนิดที่ระบุจะทำงาน
suspendUntilTasksComplete StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) หยุดชั่วคราวจนกว่างานทั้งหมดที่ระบุจะไปถึงสถานะสิ้นสุด
terminal StepResult.terminal({mutatedState}) รันของไปป์ไลน์เสร็จสิ้นแล้ว — ไม่มีขั้นตอนอีกต่อไป
failed StepResult.failed(errorMessage) ขั้นตอนล้มเหลวพร้อมข้อความข้อผิดพลาด

พฤติกรรมการลองใหม่สำหรับบอดีของโหนดที่ล้มเหลว (PipelineNodeConfig.retryPolicy; null ปิดการลองใหม่)

เขตข้อมูล ชนิด คำอธิบาย
maxAttempts int จำนวนครั้งที่ลองทั้งหมดรวมครั้งแรก (3 = ลอง 1 ครั้ง + ลองใหม่ 2 ครั้ง); ต้อง ≥ 1
backoff String linear หรือ exponential (ค่าเริ่มต้น)
initialDelayMs int การหน่วงก่อนการลองใหม่ครั้งแรก หน่วยเป็นมิลลิวินาที; การหน่วงครั้งต่อ ๆ ไปจะเพิ่มขึ้นตาม backoff

การตั้งค่าต่อโหนดที่พกอยู่ภายในนิยามของขั้นตอน (packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart) ทั้งโหนดในตัวและโหนดที่กำหนดเองใช้รูปทรงเดียวกันนี้; แต่ละบอดีอ่านเฉพาะเขตข้อมูลที่มันสนใจ

เขตข้อมูล ชนิด คำอธิบาย
prompt String? เทมเพลตพรอมป์ต์ที่แทนที่ด้วย {{key}}
script String? บอดีสคริปต์ Bash ที่แทนที่ด้วย {{key}}
agentId String? UUID ของเอเจนต์ที่ผูกกับเวิร์กสเปซที่จะสั่งงาน
inputKeys List<String> คีย์สถานะที่โหนดนี้ใช้เป็นอินพุต
repoIds List<String> รีโปที่โหนด messaging.createSpace เช็กเอาต์ (<repoId> หรือ <repoId>@<branch>) ว่างเปล่า = ไม่เอาเลย; extras['allRepos'] = ทุกรีโปในเวิร์กสเปซ ถูกละเลยบนขั้นตอนเอเจนต์
outputKey String? คีย์สถานะที่เอาต์พุตของโหนดนี้ถูกเขียนไว้ใต้คีย์นั้น
label String? ป้ายชื่อที่มนุษย์อ่านที่แสดงบนแคนวาส (ค่าเริ่มต้นคือ ID ของขั้นตอน)
outputSchema Map<String, dynamic>? JSON Schema (ชุดย่อย) ที่ค่าเอาต์พุตต้องเป็นไปตามนั้น
reducer String? กลยุทธ์การผสานเมื่อสาขาที่รันขนานกันเขียน outputKey เดียวกัน: append, mergeLists, mergeMaps, sum หรือ override (ค่าเริ่มต้น)
retryPolicy StepRetryPolicy? นโยบายการลองใหม่เมื่อบอดีล้มเหลว; null = ลองครั้งเดียว
continueOnFail bool เมื่อเป็น true ความล้มเหลวระดับ terminal จะไม่ทำให้รันล้มเหลว; ข้อผิดพลาดจะถูกพักไว้ใต้ state['_stepErrors'][stepId]
timeoutMs int? หมดเวลาแบบนาฬิกาจริงสำหรับบอดีของโหนด หน่วยเป็นมิลลิวินาที; null = ไม่มีหมดเวลา
teamId String? ทีมที่จะสั่งงาน (โหนด team.dispatch); ใช้ร่วมกับ agentId ไม่ได้
dispatchMode String? โหมดการทำงานของทีม: allParallel หรือ manager
extras Map<String, dynamic> การตั้งค่าที่เจาะจงต่อบอดีแบบอิสระ (เช่น iterableKey, templateId, ทรีเงื่อนไข)

แอกเซสเซอร์ที่ได้มา: spaceId (extras['spaceId'] — บทสนทนาที่มีอยู่แล้วที่จะทำงานในนั้น), createsConversation (extras['createConversation']), conversationTitle (extras['conversationTitle']), modeName (extras['mode'] — chat / review / plan อ่านที่โหนดที่เปิดสเปซ) และ runWhen (extras['runWhen'] — ข้ามโหนดเมื่อเงื่อนไขไม่เป็นจริง)