เครื่องมือเอเจนต์ในตัว
เหล่านี้คือเครื่องมือที่ผูกกับเซิร์ฟเวอร์ซึ่งรันไทม์เอเจนต์ในตัวลงทะเบียนไว้โดยตรง — เซิร์ฟเวอร์ภาษา การค้นหาเชิงโครงสร้าง ดีบักเกอร์ เคอร์เนล คำถาม และการควบคุมวอร์กเกอร์ — ต่างจากเครื่องมือ MCPที่มันเชื่อมเข้ามา และต่างจากเครื่องมือไฟล์ การค้นหา และเชลล์ทั่วไปจากรันไทม์ของฮาร์เนส พวกมันไม่ได้อยู่บนทะเบียน MCP: ไคลเอนต์ MCP ภายนอกจะมองไม่เห็น เพราะแต่ละตัวผูกกับทรัพยากรฝั่งเซิร์ฟเวอร์ที่มีชีวิต — โปรเซสเซิร์ฟเวอร์ภาษา อะแดปเตอร์ดีบัก อินเทอร์พรีเตอร์ — ซึ่งเป็นของรันหนึ่งครั้ง
เครื่องมือทุกตัวที่นี่จะถูกลงทะเบียนก็ต่อเมื่อทรัพยากรที่รองรับมันถูกต่อไว้สำหรับรันนั้น — ผู้ดูแลเซิร์ฟเวอร์ภาษาหรือดีบัก พาร์เซอร์ tree-sitter โรงงานเคอร์เนล พอร์ตคำถาม รายชื่อวอร์กเกอร์ vibe การตรวจหาว่ามีเซิร์ฟเวอร์ภาษาหรืออะแดปเตอร์ดีบักสำหรับเช็กเอาต์นี้หรือไม่เป็นการตรวจแยกต่างหากที่เกิดทีหลัง (status / adapters): เครื่องมือเหล่านี้ยังคงอยู่บนพื้นผิวเพื่อให้เอเจนต์ถามได้ว่าทำไมถึงใช้งานอะไรไม่ได้ แทนที่จะเดา
ระดับการอนุมัติ
หัวข้อที่มีชื่อว่า “ระดับการอนุมัติ”เครื่องมือแต่ละตัวประกาศระดับหนึ่ง และระดับนั้นเป็นตัวตัดสินว่าพื้นผิวใดเห็นมัน — ไม่ใช่แค่ว่ามันจะขึ้นพรอมป์ต์หรือไม่ โหมดแผนและเอเจนต์ย่อยแบบอ่านอย่างเดียวถูกกำกัดไว้ที่ read เครื่องมือระดับ write หรือ exec จึงหายไปจากสคีมาของพวกมันทั้งหมด
| ระดับ | ความหมาย | เครื่องมือที่นี่ |
|---|---|---|
read |
ไม่มีผลข้างเคียง | lsp, ast_grep, ask_user และ vibe_* ทั้งห้าตัว |
write |
เปลี่ยนแปลงไฟล์ | lsp_rename, ast_edit, resolve |
exec |
เริ่มหรือควบคุมโปรเซส | debug, eval |
lsp — คำค้นเซิร์ฟเวอร์ภาษา
หัวข้อที่มีชื่อว่า “lsp — คำค้นเซิร์ฟเวอร์ภาษา”ลงทะเบียนเมื่อการรันมีผู้ดูแลเซิร์ฟเวอร์ภาษาและไดเรกทอรีทำงาน ว่าเซิร์ฟเวอร์จะตอบได้จริงหรือไม่นั้นถูกตรวจตอนเรียกใช้ เป็นส่วนตัดกัน: ต้องมีมาร์กเกอร์ที่ราก และต้องค้นหาไบนารีของเซิร์ฟเวอร์เจอ อย่างใดอย่างหนึ่งเพียงอย่างเดียวแปลว่าไม่มีเซิร์ฟเวอร์เริ่มทำงาน — status บอกไว้เช่นนั้น — แทนที่จะเดาเงียบ ๆ
ตำแหน่งถูกระบุด้วย line บวกกับสตริงย่อยใน symbol ไม่ใช่ด้วยคอลัมน์ โมเดลที่ถูกขอให้หาคอลัมน์จะเดา และการเดาผิดจะไปลงที่สัญลักษณ์อีกตัวบนบรรทัดเดียวกัน — คำตอบที่ดูเหมือนถูกแต่พูดถึงคนละเรื่อง การละ symbol ในการกระทำเชิงนำทางถือเป็นข้อผิดพลาด ไม่ใช่การเดาว่าเป็นคอลัมน์แรก
| การกระทำ | อาร์กิวเมนต์ | สิ่งที่คืนกลับ |
|---|---|---|
diagnostics |
file (หรือ "*") |
ข้อผิดพลาดและคำเตือน; "*" รันตัวตรวจสอบของโปรเจกต์แทน |
definition |
file, line, symbol |
ตำแหน่งที่สัญลักษณ์ถูกประกาศ |
type_definition |
file, line, symbol |
ตำแหน่งที่ไทป์ของมันถูกประกาศ |
implementation |
file, line, symbol |
การนำไปใช้จริง |
references |
file, line, symbol |
ทุกจุดที่ถูกใช้ จำกัดที่ 50 |
hover |
file, line, symbol |
ลายเซ็นและคอมเมนต์เอกสาร |
symbols |
query หรือ file |
ค้นหาในเวิร์กสเปซด้วย query (จำกัดที่ 100); สัญลักษณ์ในเอกสารด้วย file (จำกัดที่ 200) |
code_actions |
file, line, symbol |
การแก้แบบด่วนที่เซิร์ฟเวอร์เสนอ |
status |
— | เซิร์ฟเวอร์ตัวใดกำลังทำงาน และสำหรับรากใด |
reload |
— | รีสตาร์ตเซิร์ฟเวอร์สำหรับรากนี้ |
ผลวินิจฉัยเมื่อเขียน
หัวข้อที่มีชื่อว่า “ผลวินิจฉัยเมื่อเขียน”ผลตอบแทนไม่ใช่ตัวเครื่องมือ write, edit และ apply_patch ถูกห่อไว้: หลังการเขียน ไฟล์จะถูกซิงก์และบันทึกผ่านเซิร์ฟเวอร์ภาษา และมีเพียงผลวินิจฉัยที่เพิ่งเกิดขึ้นใหม่เท่านั้นที่ถูกพับรวมเข้าไปในผลลัพธ์ของเครื่องมือ เอเจนต์จึงรู้ว่าตัวเองทำให้บิลด์พังในจังหวะที่มันพัง โดยไม่ต้องนึกขึ้นมาได้ว่าต้องถาม
ผลวินิจฉัยที่ถูกแจ้งไปแล้วจะถูกระงับด้วยทะเบียนต่อการรันหนึ่งชุดที่ยึดความรุนแรง รหัส และข้อความเป็นคีย์ — ตำแหน่งถูกตัดออกอย่างจงใจ ผลวินิจฉัยที่แค่เลื่อนลงมาสี่บรรทัดจึงไม่ถูกแจ้งซ้ำว่าเป็นของใหม่
lsp_rename — เปลี่ยนชื่อทั้งโปรเจกต์
หัวข้อที่มีชื่อว่า “lsp_rename — เปลี่ยนชื่อทั้งโปรเจกต์”เครื่องมือแยกต่างหากระดับ write ด้วยเหตุผลเดียวเท่านั้น: ระดับเป็นตัวตัดสินการมองเห็น การพับการเปลี่ยนชื่อเข้าไปใน lsp จะหมายถึงการมอบความสามารถในการเขียนรีโปใหม่ให้กับตัวสำรวจแบบอ่านอย่างเดียว หรือไม่ก็เอา hover ทุกครั้งไปไว้หลังพรอมป์ต์ขออนุมัติ
| อาร์กิวเมนต์ | ความหมาย |
|---|---|
file |
ตำแหน่งที่สัญลักษณ์อยู่ |
line |
บรรทัดที่นับจาก 1 |
symbol |
สตริงย่อยที่ระบุตัวมันบนบรรทัดนั้น |
new_name |
ชื่อที่จะเรียกมัน |
ast_grep — การค้นหาเชิงโครงสร้าง
หัวข้อที่มีชื่อว่า “ast_grep — การค้นหาเชิงโครงสร้าง”หาโค้ดด้วยรูปร่างแทนที่จะด้วยข้อความ $NAME จับคู่กับโหนดใดก็ได้ $$$NAME จับคู่กับโหนดพี่น้องที่ต่อเนื่องกัน และ $_ เป็นไวลด์การ์ดที่ไม่ผูกอะไรเลย
คุณสมบัติที่ทำให้มันเป็นตัวจับคู่แทนที่จะเป็นรีจิกซ์ที่เพิ่มขั้นตอนเข้ามา: เมทาวาริเอเบิลที่ซ้ำกันในแพตเทิร์นเดียวต้องจับข้อความเดียวกัน
ast_grep(pattern: "if ($X != null) $X.dispose()", language: "dart")จะจับคู่กับโค้ดป้องกันที่ dispose สิ่งที่มันเพิ่งตรวจสอบ และจะไม่จับคู่กับอันที่ dispose อย่างอื่น
| อาร์กิวเมนต์ | ความหมาย |
|---|---|
pattern |
เศษโค้ดที่มีเมทาวาริเอเบิล |
path |
ไฟล์หรือไดเรกทอรีที่จะค้นหา; ค่าเริ่มต้นคือทั้งเวิร์กสเปซ |
language |
id ของไวยากรณ์ที่จัดส่งมา (dart, python, rust, c, …) จะถูกอนุมานเมื่อ path ชี้ไปที่ไฟล์ |
max_results |
ค่าเริ่มต้น 50 |
ast_edit — เขียนใหม่เชิงโครงสร้าง แบบพักไว้
หัวข้อที่มีชื่อว่า “ast_edit — เขียนใหม่เชิงโครงสร้าง แบบพักไว้”การจับคู่แบบเดียวกัน บวกกับเทมเพลต rewrite ที่เมทาวาริเอเบิลถูกแทนกลับเข้าไป ไม่มีอะไรถูกเขียนลงไป การเปลี่ยนแปลงถูกพักไว้ และผลลัพธ์ระบุ edit_id
ast_edit(pattern: "dispose($X)", rewrite: "$X.dispose()", language: "dart")→ (proposed) 12 replacements in 4 files … call resolve with edit_id "edit_1"| อาร์กิวเมนต์ | ความหมาย |
|---|---|
pattern |
สิ่งที่จะจับคู่ |
rewrite |
สิ่งที่จะใส่แทน โดยมี $NAME ถูกแทนที่ |
path |
ขอบเขต; ค่าเริ่มต้นคือทั้งเวิร์กสเปซ |
language |
id ของภาษา |
resolve — คอมมิตหรือทิ้งการเปลี่ยนแปลงที่พักไว้
หัวข้อที่มีชื่อว่า “resolve — คอมมิตหรือทิ้งการเปลี่ยนแปลงที่พักไว้”| อาร์กิวเมนต์ | ความหมาย |
|---|---|
edit_id |
จากผลลัพธ์ (proposed) |
action |
accept หรือ discard |
ทุกไฟล์จะถูกตรวจเทียบกับเนื้อหาที่บันทึกไว้ตอนพักการเปลี่ยนแปลง และความไม่ตรงกันแม้แต่จุดเดียวจะปฏิเสธการเปลี่ยนแปลงทั้งชุด การเขียนใหม่เชิงโครงสร้างที่ลงไปเพียงบางส่วนจะทิ้งทรีที่คอมไพล์ไม่ผ่านทั้งรูปร่างเดิมและรูปร่างใหม่
debug — ขับเคลื่อนดีบักเกอร์
หัวข้อที่มีชื่อว่า “debug — ขับเคลื่อนดีบักเกอร์”ลงทะเบียนเมื่อการรันมีผู้ดูแลเซสชันดีบัก ไดเรกทอรีทำงาน และ id ของบทสนทนา ว่าอะแดปเตอร์จะเริ่มทำงานได้จริงหรือไม่นั้นถูกตรวจตอนเรียกใช้ ด้วยกฎส่วนตัดกันเดียวกับเซิร์ฟเวอร์ภาษา (มาร์กเกอร์ที่ราก และไบนารี) ระดับ exec; ไม่ปลอดภัยเมื่อรันขนานกัน (เซสชันคือสถานะที่อยู่ข้ามการเรียก ดังนั้น continue ที่แซง stack จะอ่านเฟรมที่ขยับไปแล้ว)
หนึ่งเซสชันต่อหนึ่งบทสนทนา พร้อม TTL แบบตายตัว (30 นาที) launch ครั้งที่สองจะถูกปฏิเสธแทนที่จะไปแทนที่ครั้งแรกอย่างเงียบ ๆ
| อ็อป | อาร์กิวเมนต์ | หมายเหตุ |
|---|---|---|
adapters |
— | อะแดปเตอร์ตัวใดใช้ได้ที่นี่ และทำไมถึงไม่ |
status |
— | มีเซสชันกำลังทำงานอยู่หรือไม่ และมันหยุดอยู่ที่ไหน |
breakpoints |
file, lines[] |
lines ว่างเปล่าจะล้างไฟล์ ตั้งไว้ก่อนเปิดโปรแกรมได้ |
launch |
program, args[] |
เปิดโปรแกรมโดยหยุดที่เบรกพอยต์ของคุณ |
attach |
port |
เชื่อมต่อกับโปรแกรมที่กำลังรันอยู่แล้ว |
continue |
thread_id? |
รันไปจนถึงจุดหยุดถัดไป |
pause |
thread_id? |
หยุดมันตรงที่มันอยู่ |
step_over / step_in / step_out |
thread_id? |
เดินไปหนึ่งขั้น |
threads |
— | id และชื่อของเธรด |
stack |
thread_id? |
เฟรม จำกัดที่ 30 |
scopes |
frame_id |
สโคปบนเฟรมหนึ่ง แต่ละอันมี reference |
variables |
reference |
สมาชิกลูก จำกัดที่ 50 ค่าจำกัดที่ 400 ตัวอักษร |
evaluate |
expression, frame_id? |
ประเมินในสโคปของเฟรมนั้นเอง |
output |
— | stdout/stderr ของโปรแกรมที่ถูกดีบัก แบบมีขอบเขต |
terminate |
— | จบเซสชันและฆ่าอะแดปเตอร์ |
อะแดปเตอร์
หัวข้อที่มีชื่อว่า “อะแดปเตอร์”| Id | คำสั่ง | มาร์กเกอร์ที่ราก |
|---|---|---|
dart |
dart debug_adapter |
pubspec.yaml |
debugpy |
python3 -m debugpy.adapter |
pyproject.toml, setup.py, requirements.txt |
lldb |
lldb-dap |
Cargo.toml, CMakeLists.txt |
delve |
dlv dap |
go.mod |
debugpy เลือก .venv/bin หรือ venv/bin ภายในโปรเจกต์เหนือ $PATH: ไพทอนที่มาจาก $PATH เป็นคนละสภาพแวดล้อม และการแอตแทชจากตัวที่ผิดจะล้มเหลวในลักษณะที่อ่านดูเหมือนโค้ดพัง
eval — อินเทอร์พรีเตอร์แบบถาวร
หัวข้อที่มีชื่อว่า “eval — อินเทอร์พรีเตอร์แบบถาวร”เซลล์ Python หรือ JavaScript ที่ตัวแปร อิมพอร์ต และข้อมูลที่โหลดไว้อยู่ต่อระหว่างการเรียก ระดับ exec; ไม่ปลอดภัยเมื่อรันขนานกัน
| อาร์กิวเมนต์ | ความหมาย |
|---|---|
code |
เซลล์ |
description |
จำเป็น 5–10 คำสำหรับป้ายในทรานสคริปต์ |
language |
python (ค่าเริ่มต้น) หรือ javascript |
reset |
ทิ้งอินเทอร์พรีเตอร์และเริ่มใหม่ที่สะอาดก่อน |
- นิพจน์สุดท้ายจะถูกสะท้อนกลับแบบที่โน้ตบุ๊กทำ
display()ทำงาน ดาต้าเฟรมของ pandas เรนเดอร์เป็นตาราง และภาพของ matplotlib กลับมาเป็นรูปภาพที่ทรานสคริปต์แสดง- สำนวนของ IPython ที่คนพิมพ์กันโดยไม่ทันคิด —
%pip,%cd,!cmd,%%bash,%%timeit— ถูกเขียนใหม่เป็นโค้ดธรรมดา%pipยังไล่sys.modulesออกด้วยimportครั้งถัดไปจึงเห็นสิ่งที่เพิ่งติดตั้งไป
เรียกเครื่องมือของคุณเองจากในเซลล์
หัวข้อที่มีชื่อว่า “เรียกเครื่องมือของคุณเองจากในเซลล์”contents = tool("read", {"path": "lib/auth.dart"})สะพานนี้กลับเข้าสู่ทะเบียนเครื่องมือของฮาร์เนส กฎคุม การอนุมัติ และตัวห่อทุกตัวจึงมีผลเหมือนกับการเรียกที่โมเดลออกเองเป๊ะ ๆ มันวิ่งบนไปป์ของเคอร์เนลเองแทนที่จะเป็นซ็อกเก็ตลูปแบ็ก: ไม่มีพอร์ต ไม่มีความลับ ไม่มีกฎการเชื่อมต่อขาออก
การหมดเวลาของเซลล์เป็นงบความไม่มีการใช้งาน (ค่าเริ่มต้น 5 นาที) และมันถูกระงับขณะมีการเรียกผ่านสะพานค้างอยู่ เซลล์ที่กระจายงานไปยังเอเจนต์ย่อยจึงไม่ถูกฆ่ากลางการกระจายงาน
ask_user — ถามคำถามกับมนุษย์
หัวข้อที่มีชื่อว่า “ask_user — ถามคำถามกับมนุษย์”ระดับ read วิธีเดียวที่การรันจะถามผู้ปฏิบัติงานได้ มันเรนเดอร์การ์ดแบบมีหมายเลขในบทสนทนาและบล็อกรอจนกว่าจะมีคนตอบ ข้าม หรือคำถามหมดเวลา ห้ามเขียนคำถามเป็นข้อความแชทเด็ดขาด — นั่นจะจบเทิร์น
| อาร์กิวเมนต์ | ความหมาย |
|---|---|
question |
สิ่งที่จะถาม |
context |
ไม่บังคับ: ทำไมคุณถึงถาม และอะไรขึ้นอยู่กับคำตอบ |
options[] |
ตัวเลือก แต่ละอันเป็น {label, description?} |
allow_free_text |
รับคำตอบที่พิมพ์เองหรือไม่ |
multi_select |
เลือกได้หลายตัวเลือกหรือไม่ |
การข้ามถือว่าสำเร็จ: ไปต่อบนสมมติฐานที่ระบุไว้และอย่าถามอีก การหมดเวลาเป็นข้อผิดพลาดที่มีคำสั่งเดียวกัน พรอมป์ต์ขออนุญาต (“ฉันทำสิ่งนี้ได้ไหม?”) เป็นด่านแยกต่างหากและเรนเดอร์เป็นการ์ดแบบเดียวกันในบทสนทนา
ลงทะเบียนเมื่อมีทั้งพอร์ตคำถามและสเปซเป้าหมายเท่านั้น หากไม่มีมนุษย์เชื่อมต่ออยู่ การเรียกจะล้มเหลวแทนที่จะบล็อกไปตลอด — ท่าทีล้มเหลวแบบปิดเดียวกับที่ prompt ของกฎคุมใช้เมื่อไม่มีผู้อนุมัติเชื่อมต่ออยู่
vibe_* — กำกับวอร์กเกอร์พื้นหลัง
หัวข้อที่มีชื่อว่า “vibe_* — กำกับวอร์กเกอร์พื้นหลัง”ลงทะเบียนเฉพาะขณะโหมด vibeเปิดอยู่ ทั้งห้าตัวเป็นระดับ read: ด่านควรอยู่ที่เครื่องมือของวอร์กเกอร์ ซึ่งการแก้ไขเกิดขึ้นจริงตรงนั้น
| เครื่องมือ | อาร์กิวเมนต์ | หมายเหตุ |
|---|---|---|
vibe_spawn |
brief, label, tier? |
คืนค่าทันที; วอร์กเกอร์ทำงานต่อไป |
vibe_send |
worker_id, message |
ต่อท้ายบรีฟแล้วรันใหม่ |
vibe_wait |
worker_id, timeout_seconds? |
บล็อกรอจนกว่ามันจะจบ |
vibe_kill |
worker_id |
หยุดมัน |
vibe_list |
— | ระดับ สถานะ เวลาที่ผ่านไป และผลลัพธ์ล่าสุด |
tier คือ fast (งานเชิงกลไกที่มีสเปกชัดเจน) หรือ good (การออกแบบ การใช้ดุลพินิจ หรือการรีวิวผลลัพธ์ของวอร์กเกอร์ระดับ fast)