AI Connect/Core concepts/Architecture

Architecture

Demandez à l’IA à propos de Vinkius

Comment AI Connect fonctionne vraiment : la chaîne de portée sur laquelle vous codez, le plan de contrôle qui provisionne l’état, le runtime MCP qui exécute chaque capacité et les règles qui gardent l’usage multi-utilisateurs correct.

AI Connect offre une seule surface pour votre code et deux plans en dessous. Vous codez contre une courte chaîne d’objets : application, utilisateur, connecteur, capacité. La plateforme exécute un plan de contrôle qui provisionne qui peut faire quoi, et un plan d’exécution, un runtime MCP, qui énumère et exécute chaque capacité. Une fois la division comprise, tout le comportement du SDK devient prévisible.

La chaîne : application, utilisateur, connecteur, capacité

typescript
const user = vinkius.user('alice_123');
const github = user.connector('github');
const capabilities = await user.capabilities();

Chaque objet n’ajoute que de la portée. Le client Vinkius porte l’identité de votre application : l’Application Key est le seul secret que vous gérez, et elle ne peut agir que pour sa propre app. user() lie un de vos utilisateurs par l’id de votre propre système d’authentification : aucun id d’utilisateur Vinkius à résoudre, synchroniser ou stocker ; la plateforme adresse tout par votre externalId. connector() lie un connecteur, et une Capability est une action concrète que cet utilisateur peut exécuter.

Créer des objets est local et peu coûteux : rien ne contacte la plateforme tant que vous n’appelez pas une opération comme connect(), status(), schema(), capabilities() ou execute(). Construire une chaîne neuve par requête garde la portée de votre code évidente.

Deux plans : contrôle et exécution

Le provisionnement et l’état vivent dans le plan de contrôle :

typescript
await user.ensure({ plan: 'pro' });           // provision the user
await github.credentials.set({ TOKEN: 'x' }); // write credentials
await github.status();                        // derived readiness
await vinkius.catalog.list();                 // discover connectors

L’exécution vit dans son propre plan. Quand connect() crée (ou trouve) la connexion de l’utilisateur, AI Connect émet exactement un token de données pour cette connexion, un identifiant vk_live_*, et renvoie l’URL du runtime qui l’intègre, une seule fois. Chaque capacité construite depuis cette connexion porte son runtime pré-lié, alors vos points d’appel ne passent jamais de coordonnées de routage : ni tokens, ni identifiants de connexion, ni endpoints.

Le token est le cœur du design. Énumérer les outils est gratuit ; chaque exécution est mesurée contre lui, donc la dépense, le trafic et les échecs sont attribuables par connexion utilisateur. C’est aussi un kill switch : quand l’utilisateur désactive ou supprime la connexion, le token meurt avec elle, et les appels échouent en sécurité. Le SDK ne réémet jamais silencieusement un token révoqué ; une connexion révoquée ne peut pas se remettre à facturer en douce.

Chaque connexion est un serveur MCP

Le runtime parle le MCP standard. Chaque utilisateur connecté devient un vrai endpoint MCP : la même surface que le SDK utilise pour énumérer et appeler les capacités est celle que n’importe quel client MCP, Claude Desktop, Cursor, vos autres agents, connecte directement. Conservez l’URL renvoyée par connect() si vous voulez donner cet endpoint à un autre client.

La même portabilité traverse la couche modèles. Neuf sous-chemins d’adaptateurs sans dépendances, d’OpenAI, Anthropic, Gemini, Vercel AI SDK, LangChain, LlamaIndex et Cloudflare Workers AI jusqu’à une sortie JSON Schema neutre, convertissent un CapabilitySet au format d’outils de votre fournisseur, avec injection d’usine plutôt que des peer dependencies. Changez de modèle, de client ou de framework : vos capacités restent les vôtres.

Les capacités portent leur propriétaire et leur route

Quand la plateforme énumère les capacités, chacune connaît déjà son connecteur, la connexion de cet utilisateur, son nom d’affichage et son schéma d’entrée :

typescript
const capability = capabilities.findCapability('github__create_issue');

console.log(capability?.rawName);      // create_issue
console.log(capability?.connector);    // github
console.log(capability?.inputSchema);  // JSON Schema of the arguments

Appeler execute() sur cet objet exécute l’action sur le GitHub de cet utilisateur, avec ses identifiants ; vous ne passez jamais un jeton, un identifiant de connexion ni un point d’accès. Les noms d’affichage sont préfixés par connecteur (github__create_issue) et personnalisables via namespaceCapability. Un CapabilitySet est un vrai tableau avec des aides ergonomiques (findCapability, forConnector), il se compose donc avec tout ce que vous faites déjà avec des tableaux. Et une capacité étant liée à l’utilisateur qui l’a produite, ne réutilisez jamais les capacités d’un utilisateur pour la requête d’un autre.

L’agrégation est tolérante aux pannes par design

user.capabilities() n’est pas un seul appel d’API. La plateforme énumère les outils de chaque connexion dans son propre runtime, alors l’agrégation est un fan-out borné sur les connexions prêtes de l’utilisateur, fusionné en un seul ensemble. Le design protège dans les deux sens : un connecteur instable ne coule pas le lot (les échecs partiels sont sautés et exposés par onConnectorError, et l’appel ne lève que si toutes les connexions ont échoué), et beaucoup de connecteurs n’ouvrent pas de sockets simultanés illimités.

Filtrez à moindre coût avec include/exclude, et quand un seul connecteur suffit, allez directement avec user.connector(slug).capabilities() : cela évite le fan-out complet.

Les identifiants sont en écriture seule, le statut est dérivé

Vous pouvez pousser des identifiants, demander ce qu’un connecteur exige (credentials.schema()) et voir quels champs sont configurés (credentials.status()), mais les valeurs secrètes ne ressortent jamais. Elles vivent dans le coffre de la plateforme, et le modèle ne reçoit jamais de secrets bruts. La préparation appartient au backend et se présente en exactement quatre états : not_connected, needs_credentials, ready, disabled. Seuls les connecteurs prêts contribuent des capacités, alors une connexion à moitié configurée ne peut jamais laisser fuiter un outil cassé dans la boucle de votre agent.

Ce que la plateforme fait à chaque appel

  • L’exécution est normalisée. Quel que soit le protocole du connecteur en dessous, REST, GraphQL ou streaming, execute() renvoie un seul résultat structuré : { content, isError }.
  • Les nouvelles tentatives sûres se font seules. L’instabilité transitoire est relancée sur les opérations idempotentes ; pour une action qui doit s’exécuter au plus une fois, passez une idempotencyKey stable et non vide à execute().
  • La gouvernance est intégrée. Chaque exécution est mesurée et observée par la surface AI Governance de la console : trafic, dépenses, échecs et posture de sécurité par connecteur et par utilisateur.

Deux canaux d’échec, une règle

execute() sépare l’action qui s’est exécutée et a signalé un problème de l’appel qui n’a jamais abouti :

typescript
const result = await capability.execute(args, { idempotencyKey });

if (result.isError) {
  // La capacité s’est exécutée et a signalé un échec : renvoyez-la à l’agent.
}

Les problèmes de plateforme lèvent une sous-classe de VinkiusError : AuthError, ConnectorNotConnectedError, RateLimitError, QuotaError, ValidationError et consorts, chacune portant status, code et requestId. Renvoyez les résultats isError à votre modèle pour qu’il récupère ; interceptez les erreurs levées pour décider ce que fait votre application. Les confondre masque si l’action a vraiment atteint le monde réel.

L’état est local à un objet

Un objet résout la connexion de l’utilisateur et son runtime à la première opération qui en a besoin, et les réutilise pendant toute la vie de cet objet : les appels répétés sur le même objet évitent la résolution. Il n’y a pas de cache global. Un objet tout neuf résout de nouveau, disconnect() efface ce que cet objet mémorisait et ResolverCache est un utilitaire optionnel que vous pouvez brancher sur votre propre mémorisation. C’est pourquoi le patron sûr est une chaîne neuve d’objets par requête ; réutiliser la même chaîne au sein d’une requête est un pur gain.

Étapes suivantes