AI Connect/Core concepts/Arquitetura

Arquitetura

Pergunte à IA sobre a Vinkius

Como o AI Connect realmente funciona: a cadeia de escopo com que você trabalha, o plano de controle que provisiona o estado, o runtime MCP que executa cada capacidade e as regras que mantêm o uso multiusuário correto.

O AI Connect tem uma superfície para o seu código e dois planos por baixo dela. Você escreve contra uma cadeia curta de handles: aplicação, usuário, conector, capacidade. A plataforma roda um plano de controle que provisiona quem pode fazer o quê, e um plano de execução, um runtime MCP, que lista e executa cada capacidade. Depois de entender a divisão, todo comportamento do SDK vira previsível.

A cadeia: aplicação, usuário, conector, capacidade

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

Cada objeto acrescenta apenas escopo. O cliente Vinkius carrega a identidade da sua aplicação: a Application Key é o único segredo que você gerencia, e ela só pode agir pelo próprio app. user() vincula um dos seus usuários pelo id do seu próprio sistema de autenticação: não existe id de usuário da Vinkius para resolver, sincronizar ou armazenar; a plataforma endereça tudo pelo seu externalId. connector() vincula um conector, e uma Capability é uma ação concreta que esse usuário pode executar.

Criar handles é local e barato: nada contata a plataforma até você chamar uma operação como connect(), status(), schema(), capabilities() ou execute(). Construir uma cadeia nova por requisição mantém o escopo do seu código evidente.

Dois planos: controle e execução

Provisionamento e estado vivem no plano de controle:

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

A execução vive em um plano próprio. Quando connect() cria (ou encontra) a conexão do usuário, o AI Connect emite exatamente um token de dados para essa conexão, uma credencial vk_live_*, e devolve a URL do runtime que o embute, uma única vez. Cada capacidade construída daquela conexão carrega o runtime pré-vinculado, então seus pontos de chamada nunca passam coordenadas de roteamento: nem tokens, nem IDs de conexão, nem endpoints.

O token é o coração do design. Listar ferramentas é gratuito; cada execução é medida contra ele, então gasto, tráfego e falhas são atribuíveis por conexão de usuário. Ele também é um kill switch: quando o usuário desativa ou exclui a conexão, o token morre junto, e as chamadas falham fechadas. O SDK nunca reemite silenciosamente um token revogado; uma conexão revogada não pode começar a faturar de novo escondida.

Cada conexão é um servidor MCP

O runtime fala MCP padrão. Isso torna cada usuário conectado um endpoint MCP real: a mesma superfície que o SDK usa para listar e chamar capacidades é o que qualquer cliente MCP, Claude Desktop, Cursor, seus outros agentes, conecta diretamente. Persista a URL que connect() devolve quando quiser entregar esse endpoint a outro cliente.

A mesma portabilidade atravessa a camada de modelos. Nove subpaths de adapter sem dependências, de OpenAI, Anthropic, Gemini, Vercel AI SDK, LangChain, LlamaIndex e Cloudflare Workers AI até uma saída JSON Schema neutra, convertem um CapabilitySet no formato de tools do seu provedor, com injeção de fábrica em vez de peer dependencies. Troque de modelo, cliente ou framework: suas capacidades continuam suas.

Capacidades carregam seu dono e sua rota

Quando a plataforma lista capacidades, cada uma já conhece seu conector, a conexão daquele usuário, seu nome de exibição e seu schema de entrada:

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

Chamar execute() nesse objeto executa a ação no GitHub daquele usuário, com as credenciais daquele usuário; você nunca passa um token, um ID de conexão ou um endpoint. Os nomes de exibição têm namespace por conector (github__create_issue) e são personalizáveis via namespaceCapability. Um CapabilitySet é um array de verdade com helpers ergonômicos (findCapability, forConnector), então ele se compõe com tudo que você já faz com arrays. E como uma capacidade está vinculada ao usuário que a produziu, nunca reutilize objetos de capacidade de um usuário na requisição de outro.

A agregação é tolerante a falhas por design

user.capabilities() não é uma única chamada de API. A plataforma lista as ferramentas de cada conexão no runtime dela, então a agregação é um fan-out limitado sobre as conexões prontas do usuário, mesclado em um único conjunto. O design protege nos dois sentidos: um conector instável não afunda o lote (falhas parciais são puladas e expostas por onConnectorError, e a chamada só lança se todas as conexões falharem), e muitos conectores não abrem sockets ilimitados ao mesmo tempo.

Filtre barato com include/exclude, e quando precisar de um único conector, vá direto com user.connector(slug).capabilities(): ele pula o fan-out completo.

Credenciais são somente de escrita, status é derivado

Você pode enviar credenciais, perguntar o que um conector exige (credentials.schema()) e ver quais campos estão configurados (credentials.status()), mas valores de segredo nunca voltam. Eles vivem no cofre da plataforma, e o modelo nunca recebe segredos brutos. A prontidão é de responsabilidade do backend e se apresenta em exatamente quatro estados: not_connected, needs_credentials, ready, disabled. Só conectores prontos contribuem capacidades, então uma conexão meio configurada nunca vaza uma tool quebrada no loop do seu agente.

O que a plataforma faz em cada chamada

  • A execução é normalizada. Seja qual for o protocolo do conector por baixo, REST, GraphQL ou streaming, execute() devolve um único resultado estruturado: { content, isError }.
  • Repetições seguras acontecem sozinhas. Instabilidade transitória é repetida automaticamente em operações idempotentes; para uma ação que deve rodar no máximo uma vez, passe um idempotencyKey estável e não vazio para execute().
  • A governança é embutida. Cada execução é medida e observada pela superfície de AI Governance do console: tráfego, gasto, falhas e postura de segurança por conector e por usuário.

Dois canais de falha, uma regra

execute() separa a ação que rodou e reportou um problema da chamada que nunca se completou:

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

if (result.isError) {
  // A capacidade rodou e reportou falha: devolva isso ao agente.
}

Problemas da plataforma lançam uma subclasse de VinkiusError: AuthError, ConnectorNotConnectedError, RateLimitError, QuotaError, ValidationError e afins, cada uma com status, code e requestId. Devolva resultados isError ao seu modelo para que ele se recupere; capture erros lançados para decidir o que a aplicação faz. Confundir os dois esconde se a ação chegou de fato ao mundo real.

O estado é local ao handle

Um handle resolve a conexão do usuário e o runtime dela na primeira operação que precisa, e reaproveita ambos pelo resto da vida daquele handle: chamadas repetidas no mesmo handle pulam a resolução. Não existe cache global. Um handle recém-criado resolve de novo, disconnect() limpa o que aquele handle lembrava e ResolverCache é um utilitário opcional que você pode plugar na sua própria memoização. Por isso o padrão seguro é uma cadeia nova de handles por requisição; reaproveitá-la dentro da mesma requisição é lucro puro.

Próximos passos