Recherche/Ajouter des fournisseurs d’IA et des bases vectorielles à un framework d’IA modulaire en Rust

Ajouter des fournisseurs d’IA et des bases vectorielles à un framework d’IA modulaire en Rust

Pour étendre un framework Rust compatible avec de nombreux fournisseurs d’IA. L’IA suit les traits et builders existants, garde le support WebAssembly, fait agir les hooks pareil avec ou sans streaming et vérifie que les cassettes n’ont pas de clés d’API.

Pour utiliser ces règles d'IA
## Ne changer que le périmètre demandé et ne pas faire de commit sans demande - Lis l’implémentation, les manifestes, les tests et la documentation publique existants avant de modifier le code. - Maintiens chaque modification dans le périmètre demandé par l’utilisateur. - Préfère les traits, builders, modules et types d’erreur existants aux abstractions parallèles. - N’ajoute ni TODO, ni stub, ni comportement provisoire, ni API publique spéculative. - Ne crée pas de commit, ne stage pas de modifications, ne fais pas de push, ne crée pas de branche et n’ouvre pas de pull request sans demande explicite de l’utilisateur. - Préserve les modifications sans rapport apportées par l’utilisateur et contourne prudemment un arbre de travail modifié. - Évite les refactorisations sans rapport, même si une conception voisine pourrait être améliorée. - Distingue les règles destinées aux contributeurs des règles d’ingénierie propres au dépôt et respecte les deux. - Arrête-toi si l’intention produit nécessaire ou une autorisation externe fait défaut. ## Garder cohérents les crates et les feature flags dans tout le workspace - Maintiens le crate de façade publique, le crate central, les intégrations complémentaires, les macros derive, les exemples et les tests dans leurs rôles établis. - Fais réexporter les API centrales par la façade et expose les crates complémentaires facultatifs au moyen de feature flags. - Vérifie le manifeste du workspace et les exports de la façade avant de modifier les features publiques, les intégrations ou les chemins de modules. - Place les intégrations de fournisseurs et de bases vectorielles dans des crates complémentaires, sauf raison architecturale solide d’appartenance au cœur. - Distingue les exemples du workspace, les exemples propres à chaque crate et les tests d’intégration. - Lors de l’ajout d’un crate complémentaire, mets à jour selon les besoins la dépendance racine, la feature, la réexportation de façade, les exemples, le README et la documentation du crate. - Assure-toi que les combinaisons de features se compilent sans exposer de modules indisponibles. - Synchronise la documentation publique entre la façade et les crates complémentaires concernés. - Ne décris aucun chemin de module ni aucune feature avant confirmation par le code et les manifestes. ## Construire sur les traits communs plutôt que sur des versions par fournisseur - Construis les intégrations sur les traits centraux du framework pour la complétion, les embeddings, les index vectoriels et les outils appelables. - Ne crée pas d’alternative propre à un fournisseur pour un trait existant commun à plusieurs fournisseurs. - Suis le modèle de builder établi pour les types publics configurables. - Maintiens une construction fluide et typée, achevée uniquement après une étape de build explicite. - Utilise une architecture de client générique qui sépare les extensions du fournisseur du transport HTTP sous-jacent. - Déclare explicitement les capacités du fournisseur afin que les comportements non pris en charge échouent à la compilation. - Représente les capacités absentes par un type marqueur volontaire, et non par une supposition à l’exécution. - Préserve les relations de types de clé API entre les builders du fournisseur et les alias publics de client. - Garde les types de request et de response propres au fournisseur derrière des limites de conversion. ## Garder le code asynchrone partagé fonctionnel sous WebAssembly - Préserve la prise en charge de WebAssembly dans les traits, futures, erreurs et intégrations partagés. - Utilise les abstractions de compatibilité du framework au lieu de contraintes `Send` et `Sync` brutes lorsque les cibles diffèrent. - Utilise le type boxed-future portable prévu pour les futures renvoyés dynamiquement. - Applique les contraintes natives de sécurité des threads uniquement aux cibles qui les prennent en charge. - Garde les erreurs boxed de WebAssembly exemptes de contraintes exclusivement natives non prises en charge. - Teste les signatures de types natives et celles destinées à WebAssembly après toute modification de traits partagés. - Évite d’ajouter une dépendance ou une API qui exclut silencieusement une cible prise en charge. - Limite la compilation conditionnelle à un périmètre restreint et explique la différence entre les cibles. - Assure-toi que les API de fournisseurs, de bases vectorielles et de hooks utilisent le même contrat de portabilité. ## Utiliser des types d’erreur explicites et documenter chaque nouvelle API publique - N’utilise pas `String` comme type d’erreur pour une nouvelle API susceptible d’échouer. - Définis des enums d’erreur explicites et préserve les détails utiles de la réponse du fournisseur au moyen des helpers d’erreur du framework. - Préfère `?` et des conversions explicites à la perte manuelle du contexte d’erreur. - N’utilise `unwrap()` ou `expect()` que si l’impossibilité découle clairement de l’invariant environnant. - Ajoute une documentation d’élément à chaque nouveau type, fonction, trait et méthode publics. - Ajoute une documentation de module à chaque nouveau module public. - Maintiens les exemples conformes aux API réelles, constantes de modèles, chemins de modules et feature flags. - Marque les exemples comme non exécutables lorsqu’ils nécessitent des identifiants ou des services externes. - Mets à jour les fichiers README et la documentation au niveau du crate dès que le comportement public change. ## Ajouter un nouveau fournisseur d’IA en suivant le plus proche qui existe déjà - Étudie le fournisseur existant le plus proche avant d’en implémenter ou d’en modifier un autre. - Ajoute les types d’extension et de builder du fournisseur, son implémentation et une déclaration explicite de capacités. - Prends en charge la construction depuis des valeurs d’environnement et des valeurs directes lorsque le framework expose les deux voies. - Maintiens les alias publics de client et de builder cohérents avec le type de clé API du builder du fournisseur. - Utilise des types marqueurs explicites pour les identifiants ou l’authentification et masque les valeurs sensibles dans l’affichage de debug. - Convertis les requests du framework vers le véritable format d’échange du fournisseur, puis les responses vers les types du framework. - N’ajoute le streaming que lorsque le fournisseur le prend réellement en charge et préserve ses erreurs au moyen des helpers standard. - Respecte les conventions de télémétrie et les traits d’extension établis. - N’invente aucun champ de request ou de response absent de l’API réelle du fournisseur. - Ajoute des tests ou exemples ciblés qui démontrent le comportement pris en charge. ## Intégrer une base vectorielle avec de vrais filtres et des résultats de recherche clairs - Place une intégration de base vectorielle dans un crate complémentaire, sauf justification de son appartenance au cœur. - Implémente à la fois la recherche qui renvoie des résultats et celle qui renvoie uniquement des identifiants. - Utilise un type de filtre reflétant les véritables capacités de filtrage du backend. - Renvoie les variantes d’erreur de base vectorielle du framework plutôt que des erreurs textuelles improvisées. - Applique les mêmes contraintes asynchrones portables que le framework central. - Rends explicites les conversions de score, document, identifiant et métadonnées. - Définis l’ordre, la limite, le résultat vide et le comportement en cas d’erreur du backend. - Teste les filtres, l’ordre de classement, les limites de résultats, les enregistrements absents et les échecs de conversion. - Documente les features, identifiants, index et configurations externes nécessaires sans incorporer de secrets. ## Définir les actions permises pour chaque événement de hook - Modélise les hooks comme des observateurs et des pilotes du cycle de vie limités à une exécution. - Transmets à chaque événement un contexte d’exécution comprenant l’identité de l’exécution, le tour, le mode streaming, l’identité de l’agent et l’état de travail partagé. - Donne à chaque événement son propre type d’action afin que les combinaisons non prises en charge échouent à la compilation. - Permets aux hooks d’appel de complétion de modifier une request ou d’arrêter le traitement. - Permets aux hooks d’appel et de résultat d’outil de réécrire les valeurs pour les hooks suivants, avec skip ou stop comme actions terminales lorsqu’elles sont définies. - Représente le traitement des appels d’outil invalides par des choix explicites fail, retry, repair, skip et stop. - Limite les événements d’observation pure à continue ou stop. - Enregistre les hooks d’observation avant les hooks de pilotage lorsque les actions stop interrompent la pile. - Documente les actions qui transforment les données, celles qui les accumulent et celles qui terminent le traitement. ## Combiner les hooks empilés de la même façon avec ou sans streaming - Préserve la sémantique de composition propre à chaque événement lorsque les hooks sont imbriqués ou empilés. - Fusionne les modifications de requests de complétion dans l’ordre d’enregistrement. - Ajoute le contexte supplémentaire, fusionne superficiellement les paramètres additionnels et calcule l’intersection des ensembles d’outils actifs. - Applique la règle du dernier rédacteur uniquement aux champs scalaires et d’historique documentés, et avertis lorsqu’un remplacement est significatif. - Limite chaque modification de request à un seul tour ; ne la rends jamais persistante par accident. - Transmets les réécritures d’appels et de résultats d’outils à tous les hooks suivants. - Arrête immédiatement l’évaluation de la pile lorsqu’une action terminale l’exige. - Fais partager le même pilote de cycle de vie aux surfaces avec et sans streaming. - Teste un comportement identique des hooks par les points d’entrée avec et sans streaming. - Ajoute des tests de composition pour les piles imbriquées, conflits de fusion, chaînes de réécriture, skip et stop. ## Choisir le plus petit test de non-régression et utiliser des cassettes pour les appels aux fournisseurs - Ajoute une couverture de non-régression dans le plus petit périmètre fiable. - Préfère un test unitaire près de l’implémentation pour les défauts isolés de conversion ou de logique. - Utilise des tests de fournisseur appuyés par des cassettes lorsque le comportement dépend du trafic de requests et de responses du fournisseur. - N’utilise des tests live ignorés que si une relecture déterministe de cassette ne peut pas représenter le comportement. - Lis le guide de test du dépôt avant d’ajouter, modifier, enregistrer ou relire des tests de fournisseurs. - Relis les cassettes par défaut afin que les tests normaux ne nécessitent aucun identifiant de fournisseur. - Limite l’exécution des tests au fournisseur et au comportement modifiés. - Couvre les comportements avec et sans streaming lorsque les deux surfaces existent. - Préserve le mode d’échec d’origine dans l’assertion de non-régression. ## N’enregistrer des cassettes que pour le test visé et vérifier qu’elles ne contiennent aucun secret - Traite le mode d’enregistrement comme une opération externe, utilisant des identifiants et remplaçant des fichiers. - Exige les identifiants du fournisseur concerné avant l’enregistrement et ne les expose jamais dans la sortie. - N’enregistre que le test du fournisseur visé afin de réduire les modifications sans rapport dans les fixtures. - Inspecte manuellement chaque diff de cassette avant de le présenter ou de le committer. - Refuse les fixtures contenant des clés API, identifiants bearer, cookies, identifiants de compte ou autres valeurs sensibles. - Retire les variations sans rapport des requests et responses au lieu d’accepter une fixture bruyante. - Garde les contrôles automatiques de nettoyage et de sécurité actifs, sans les considérer comme un substitut à l’inspection. - Préserve les données de relecture déterministes tout en masquant les secrets et métadonnées instables. - Ne remplace jamais les fixtures uniquement pour faire réussir un test en échec sans expliquer le changement de comportement. ## Lancer les vérifications du plus ciblé au plus large et signaler ce qui n’a pas été vérifié - Exécute d’abord les plus petits contrôles utiles, puis élargis-les selon le périmètre touché et le risque. - Formate le workspace et exécute les lints sur toutes les cibles et features concernées. - Exécute les tests ciblés avant les tests étendus du workspace. - Génère la documentation sans dépendances lorsque les API publiques ou les documents changent. - Vérifie la compatibilité native et WebAssembly lorsque des contraintes ou futures partagés changent. - Confirme que les champs d’échange du fournisseur correspondent à l’API réelle et que les diffs de cassette ne contiennent aucun secret. - Confirme que la sémantique des hooks est identique sur les surfaces avec et sans streaming. - Ne déclare pas la tâche terminée tant qu’un contrôle obligatoire échoue. - Si une commande ne peut pas être exécutée, explique pourquoi et indique exactement ce qui reste non vérifié. - Rapporte les surfaces modifiées, les contrôles exécutés, les résultats observés, les risques résiduels et le périmètre volontairement exclu.