Aller au contenu

Rechercher du code avec le graphe de code

Ce guide montre comment faire entrer un dépôt dans le graphe de code, puis comment s’en servir pour répondre à la question que vous vous posez réellement avant une refactorisation : qu’est-ce qui dépend de ceci ?

Le graphe de code est une base de symboles et d’arêtes construite en analysant vos checkouts enregistrés avec tree-sitter. Ses outils s’adressent aux agents : vous y accédez en demandant à un agent.

Le graphe indexe Dart, JavaScript, TypeScript, TSX, PHP, Python, Rust, Zig, C, C++, Go, Java, Ruby, C#, Swift, Kotlin, R, Assembly, MATLAB et Ada. Les fichiers dans toute autre langue ne sont pas analysés et n’apparaissent donc pas dans search_code, code_symbol, code_callers, code_callees ni code_impact.

Deux autres éléments déterminent ce qui est indexé :

  • Dans un arbre de travail git, l’énumération s’en remet à git ls-files --cached --others --exclude-standard, de sorte que chaque .gitignore, chaque fichier d’exclusion imbriqué, .git/info/exclude et le fichier d’exclusions global sont respectés. C’est ce qui tient node_modules et les sorties de compilation hors du graphe.
  • Le Dart généré est écarté quoi qu’il arrive. Les fichiers générés sont généralement versionnés, donc git seul ne les exclurait pas, et ils sont modifiés à chaque exécution de génération de code.

L’enregistrement d’un checkout déclenche RepoAdded, qui lance automatiquement le pipeline index_code pour celui-ci. Voir Ajouter des dépôts à un espace de travail.

Pour réindexer à la main :

  1. Ouvrez Paramètres → Espace de travail → Dépôts.
  2. Cliquez sur le bouton Indexer le code sur la ligne du dépôt.
  3. Pendant l’exécution, le bouton affiche les fichiers traités sur le total, avec une commande d’annulation. Une fois terminé, il se stabilise en une coche accompagnée du nombre de symboles.

Le graphe est partitionné par espace de travail, par dépôt et par checkout : le checkout lié constitue une partition, et chaque arbre de travail d’espace a la sienne (identifiée par son identifiant de dépôt isolé).

Deux limitations méritent d’être connues, car elles expliquent une attente qui ressemble à un blocage :

  • Le surveillant de fichiers n’admet qu’une exécution d’indexation à la fois sur l’hôte : un second checkout attend. Le pipeline index_code est plafonné séparément à une exécution par espace de travail, donc deux dépôts du même espace de travail font la queue ; des espaces de travail différents peuvent indexer en parallèle. L’indexeur lui-même sérialise deux exécutions d’un même checkout, afin qu’un démarrage de pipeline et un balayage du surveillant ne puissent pas l’analyser deux fois.
  • Les arbres de travail appartenant à des espaces dormants (aucun message depuis une semaine) ne sont ni surveillés ni indexés. Les checkouts liés restent surveillés. Une décision de non-indexation est revérifiée au bout de cinq minutes, de sorte qu’un espace redevenu actif est repris en charge.

Demandez à un agent de lancer la recherche. L’outil est search_code et il exige à la fois un espace de travail et un dépôt :

search_code(workspace_id: "...", repo_id: "...", query: "authentication middleware")

Les identifiants de dépôt proviennent de list_repos. L’argument facultatif mode prend les valeurs keyword, semantic ou hybrid et vaut par défaut hybrid : BM25 sur les noms, les signatures et les commentaires de documentation, fusionné avec la similarité vectorielle.

Chaque résultat porte l’id du symbole, son nom, son nom qualifié, son type, son chemin de fichier, ses lignes de début et de fin, et sa signature lorsqu’il en a une. L’id est la référence que vous transmettez à tous les autres outils de cette page.

Quand vous connaissez le nom exact, recherchez-le directement à la place :

code_symbol(workspace_id: "...", repo_id: "...", name: "MyClass")

Les deux prennent un symbol_id issu d’un résultat de recherche, plus un limit facultatif (50 par défaut) :

code_callers(workspace_id: "...", symbol_id: "...")
code_callees(workspace_id: "...", symbol_id: "...")

code_callers renvoie les symboles ayant une arête entrante vers celui-ci ; code_callees renvoie ceux dont il dépend.

C’est l’outil pour lequel toute cette page existe :

code_impact(workspace_id: "...", symbol_id: "...", depth: 3)

Il calcule le rayon de dépendance inverse : tout ce qui dépend directement ou indirectement du symbole le long des arêtes calls, extends et implements (les imports, les mixins et les références génériques sont stockés dans le graphe mais ne sont pas parcourus ici). depth est le nombre maximal de sauts, entre 1 et 6, avec 2 par défaut.

Le résultat comporte trois champs :

  • root — le symbole que vous avez demandé
  • impacted — l’ensemble atteignable, y compris la racine à la profondeur 0, chacun portant sa depth depuis la racine
  • edgeCount — le nombre d’arêtes franchies par le parcours, sous forme de compteur plutôt que les arêtes elles-mêmes

Lancez-le avant de renommer ou de modifier une signature, et donnez à l’agent la liste des éléments impactés comme périmètre.

Les résultats sont vérifiés par rapport à la copie de travail de l’appelant

Section intitulée « Les résultats sont vérifiés par rapport à la copie de travail de l’appelant »

Pour un appelant agent, l’id de l’espace est injecté automatiquement et les résultats sont vérifiés par rapport à la copie de travail de cet espace. Un symbole dont le fichier n’existe plus dans l’arbre de l’appelant est omis, et la réponse porte un compteur staleOmitted ainsi qu’une note indiquant que l’index est périmé pour ces symboles.

C’est pourquoi vous et un agent pouvez obtenir des réponses différentes à la même requête, et pourquoi un agent d’un espace peut obtenir une réponse différente de celle d’un agent d’un autre espace. Toutes les conversations d’un espace partagent ce même arbre de travail. La vérification échoue en mode ouvert : une réponse périmée est préférée à une réponse vide.

Demandez à un agent d’exécuter code_impact (ou review_studio.blastRadius) lorsque vous voulez le rayon d’impact d’une modification. Voir Calcul de revue.

La recherche sémantique exige le modèle d’embedding

Section intitulée « La recherche sémantique exige le modèle d’embedding »

Les symboles et les faits sont vectorisés au moment de l’écriture, et uniquement lorsque le modèle d’embedding sur l’appareil est installé. D’ici là, mode: "semantic" et la moitié sémantique du mode hybrid n’ont rien à quoi se comparer, et la recherche se fait de fait uniquement par mots-clés.

Installez le modèle dans Paramètres → Serveur → Diagnostics et confidentialité → Recherche sémantique avant d’indexer. Les symboles reçoivent un vecteur lorsque leur fichier est ingéré.

Notez aussi que toute reconstruction du binaire du serveur réinstalle les dylibs des grammaires et modifie leur mtime, ce qui invalide chaque point de contrôle de l’index et force un nouveau parcours complet de chaque checkout à l’exécution suivante. Il recalcule les hachages, mais ne réextrait pas les fichiers inchangés.

Types de symboles : function, method, class, field, enum, constructor, getter, setter, typedef, extension, mixin, variable.

Types d’arêtes : calls, imports, extends, implements, mixes in, references.

Les signatures de référence de ces outils se trouvent dans Outils MCP.