Intelligence pentru cod
Control Center îi dă unui agent patru moduri de a înțelege codul dincolo de simpla citire a lui. Ele răspund la întrebări cu adevărat diferite, iar motivul pentru care sunt patru, nu unul, este că niciun mecanism unic nu răspunde la toate.
| Mecanism | Răspunde la | Costuri |
|---|---|---|
| Graful de cod | Ce se află aici și de ce depinde | O trecere de indexare; interogare ieftină |
| Serverul de limbaj | Chiar se compilează asta și ce tip este acesta | Un proces de server per proiect |
| Căutarea structurală | Unde apare această FORMĂ | O analiză sintactică per fișier |
| Depanatorul | Ce era adevărat în acel moment, în acel cadru | Un proces oprit |
Golul pe care îl acoperă serverul de limbaj
Secțiune intitulată „Golul pe care îl acoperă serverul de limbaj”Graful de cod este construit cu tree-sitter: simboluri, muchii de apel, o rază de impact. Este rapid, este ieftin și nu știe nimic despre tipuri. Nu îți poate spune dacă apelul pe care tocmai l-ai scris se compilează, dacă acel câmp există pe obiect sau dacă redenumirea ta a ratat un reexport.
Fără un server de limbaj, un agent află la momentul testelor — sau niciodată. Scrie ceva plauzibil, își vede mai departe de treabă, iar eșecul iese la suprafață trei tururi mai târziu, atașat de o altă modificare.
Așadar, câștigul nu este de fapt instrumentul lsp. Ci faptul că write, edit și apply_patch sunt înfășurate: după fiecare scriere, fișierul trece prin serverul de limbaj, iar diagnosticele nou introduse sunt incluse în rezultatul instrumentului. Agentul află că a stricat compilarea în chiar momentul în care a stricat-o, indiferent dacă i-a trecut prin minte să întrebe.
Numai diagnosticele noi
Secțiune intitulată „Numai diagnosticele noi”A repeta ce i s-a spus deja agentului este mai rău decât să nu spui nimic: umple rezultatul cu zgomot pe lângă care agentul învață să treacă, iar singura eroare nouă se pierde odată cu el. Un registru per rulare ține evidența a ce s-a raportat, indexat după severitate, cod și mesaj — nu după poziție, așa că un diagnostic care doar s-a mutat patru rânduri mai jos nu este raportat din nou ca fiind nou.
Leneș și sincer în privința absenței sale
Secțiune intitulată „Leneș și sincer în privința absenței sale”Niciun server nu pornește la boot. Unul pornește la prima cerere care are nevoie de el, care este aproape întotdeauna prima editare a unui fișier pe care îl revendică, iar cele inactive sunt curățate. O gazdă care nu atinge niciodată Dart nu pornește niciodată un analizor.
Detecția este o intersecție: un marker de rădăcină trebuie să existe în copia locală și binarul trebuie să se rezolve. Un marker singur spune „acest proiect este Python” și nimic despre dacă serverul este instalat; un binar care se rezolvă singur spune că gazda are un lanț de instrumente și nimic despre această copie locală. Numai ambele împreună înseamnă că o interogare poate reuși, iar un instrument care este oferit și eșuează mereu este mai rău decât unul care lipsește.
De ce căutare structurală, când există grep
Secțiune intitulată „De ce căutare structurală, când există grep”grep potrivește caractere. Este instrumentul potrivit pentru un nume și cel greșit pentru o formă.
Un șablon structural este analizat sintactic de aceeași gramatică precum fișierul, așa că dispose($X) găsește apelul oricum ar fi spațiat, împachetat sau rupt pe linii și nu potrivește niciodată aceleași caractere dintr-un literal de șir sau dintr-un comentariu.
Proprietatea care îl face mai mult decât o expresie regulată cu pași în plus este că o metavariabilă repetată într-un șablon trebuie să capteze același text:
if ($X != null) $X.dispose()potrivește o gardă care eliberează exact ce a testat și nu potrivește una care eliberează altceva. Este o clasă de erori pe care nu o poți exprima textual deloc.
Rulează pe tree-sitter-ul deja linkat
Secțiune intitulată „Rulează pe tree-sitter-ul deja linkat”Nu există un al doilea motor. cc_natives încarcă deja tree-sitter și gramaticile sale pentru graful de cod, cu un cache de interogări compilate și un tabel de limbaje. Potrivitorul este Dart pur peste arbori care oricum erau analizați sintactic. Un al doilea motor structural ar însemna un al doilea parser, un al doilea set de gramatici de construit și de pregătit pe fiecare platformă și două răspunsuri la „ce este o expresie de apel”.
Un fragment are nevoie de un loc unde să stea
Secțiune intitulată „Un fragment are nevoie de un loc unde să stea”O gramatică definește doar ce este un întreg fișier. Analizat simplu, la nivelul superior al Dart, dispose(x) este o semnătură de funcție perfect validă — o declarație numită dispose care ia un parametru x — fără nicio eroare care să trădeze asta. Un potrivitor construit pe acea analiză caută declarații, nu găsește niciun apel și raportează „nicio potrivire” pentru un șablon care nu era citit niciodată așa cum arată.
Așadar, un șablon este încercat într-o scară de încadrări — instrucțiune, expresie, membru de clasă, nivel superior — iar prima care îl acceptă câștigă. Un fragment pe care nu îl acceptă niciun context este raportat ca neanalizabil, în loc să fie căutat și pur și simplu negăsit.
De ce o rescriere pregătește în loc să scrie
Secțiune intitulată „De ce o rescriere pregătește în loc să scrie”O rescriere structurală este cea mai largă modificare pe care o poate face un agent: un șablon, patruzeci de fișiere și nimeni nu citește rezultatul linie cu linie — nici modelul, nici persoana care a cerut-o. Să o scrii și să raportezi „gata” înseamnă că prima privire sinceră asupra modificării este un git diff de după.
Așa că ast_edit raportează ce ar face — numărul, fișierele, locurile potrivite — iar modificarea se aplică doar când resolve o comite. Acesta este și ce permite ca un diff și un Acceptă/Renunță să stea în fața unui om înainte ca ceva să ajungă pe disc.
Commit-ul este totul-sau-nimic și fiecare fișier este verificat față de conținutul capturat la momentul pregătirii. Între pregătire și commit, agentul poate să fi editat manual unul dintre acele fișiere, o trecere de diagnostice poate să îl fi rescris sau un formator poate să îl fi atins — dacă s-ar comite oricum, acea muncă ar fi pierdută, iar diff-ul ar părea intenționat. Orice nepotrivire refuză întreaga modificare, pentru că o rescriere structurală aplicată parțial lasă un arbore care nu se compilează în niciuna dintre forme.
La ce răspunde un depanator și nu poate răspunde o instrucțiune de tipărire
Secțiune intitulată „La ce răspunde un depanator și nu poate răspunde o instrucțiune de tipărire”Bucla cu instrucțiuni de tipărire este: adaugi o tipărire, rulezi din nou totul, citești rezultatul, ștergi tipărirea. Costă o rulare completă de teste per întrebare și răspunde doar la întrebarea la care te-ai gândit înainte de a rula.
Un cadru oprit răspunde deodată la orice întrebare despre acel moment — fiecare variabilă locală, fiecare apelant și o expresie evaluată în scopul propriu al cadrului. Pentru un proces blocat sau o defecțiune care se reproduce o dată la zece rulări, asta este diferența dintre o după-amiază și un minut.
Delimitat ca un țarc, și din același motiv
Secțiune intitulată „Delimitat ca un țarc, și din același motiv”Un adaptor de depanare deține un proces oprit care ține tot ce ține procesul respectiv — un port, o blocare, o conexiune la baza de date. O sesiune pe care nu o conduce nimeni este o scurgere care supraviețuiește turului care a pornit-o. Prin urmare există un TTL strict, exact o sesiune per conversație, iar un al doilea launch este refuzat în loc să îl înlocuiască silențios pe primul: un agent care pornește un al doilea fără să îl încheie pe primul și-a pierdut aproape sigur urma primului.
Un transport, două protocoale
Secțiune intitulată „Un transport, două protocoale”Debug Adapter Protocol împarte cu Language Server Protocol încadrarea Content-Length și nimic deasupra ei — chei de corelare diferite, o formă de eșec diferită și un al treilea tip de mesaj (evenimente) fără echivalent în LSP. Încadrarea trăiește într-un singur loc; protocoalele stau separat deasupra ei.
A scrie încadrarea de două ori ar însemna două răspunsuri la „un mesaj se întinde pe două segmente”, „un segment conține trei mesaje” și „serverul a scris un banner la stdout înainte de primul său cadru”, iar doar unul dintre ele ar primi corectura.
- Caută cod cu graful de cod — partea de simboluri și de impact
- Depanează un test eșuat cu un agent — depanatorul, cap-coadă
- Refactorează codul structural —
ast_grepșiast_edit - Instrumente agent integrate — fiecare operație și argumentul ei