Search

Search the documentation

Protobox
Use cases

Agent tool-calling

Hand a connected user's tools to OpenAI, Anthropic, the Vercel AI SDK, LangChain, or Google GenAI — and run the model's tool-calls server-side with that user's credentials.

Scenario: Acme's in-product assistant chats with a support rep. Mid-conversation it needs to search the rep's connected HubSpot, then send a Gmail reply — as that rep, with that rep's credentials, without Acme writing a single provider client.

One line per framework

An adapter converts an entity's tools into your framework's native format and executes the model's tool-calls back through the platform:

const user = protobox.entity('user_123');

const gh = user.forLLM('anthropic', { integrationId: 'gmail' });
const tools = await gh.tools();       // Anthropic tool definitions
// ...model call...
const results = await gh.run(message.content); // executed server-side

Five providers ship: 'openai', 'anthropic', 'vercel', 'langchain', and 'google-genai'.

Full loop (Anthropic)

import Anthropic from '@anthropic-ai/sdk';
import { ProtoboxSDK } from '@protoboxai/sdk';

const anthropic = new Anthropic();
const protobox = new ProtoboxSDK({ apiKey: process.env.PROTOBOX_API_KEY! });

const user = protobox.entity('user_123');
const hub = user.forLLM('anthropic', { integrationId: 'hubspot' });

const messages: Anthropic.MessageParam[] = [
  { role: 'user', content: 'Find the Initech account and summarize open deals.' },
];

let response = await anthropic.messages.create({
  model: 'claude-sonnet-5',
  max_tokens: 1024,
  messages,
  tools: await hub.tools(),
});

while (response.stop_reason === 'tool_use') {
  // Executes every tool_use block through Protobox with user_123's credential
  const toolResults = await hub.run(response.content);

  messages.push({ role: 'assistant', content: response.content });
  messages.push({ role: 'user', content: toolResults });

  response = await anthropic.messages.create({
    model: 'claude-sonnet-5',
    max_tokens: 1024,
    messages,
    tools: await hub.tools(),
  });
}

Vercel AI SDK

maxSteps gives you the loop for free:

import { generateText } from 'ai';

const vc = user.forLLM('vercel', { integrationId: 'gmail' });

const { text } = await generateText({
  model,
  prompt: 'Reply to the latest email from Initech and confirm the renewal call.',
  tools: await vc.tools(),   // each tool carries its own execute() closure
  maxSteps: 5,
});

OpenAI

const oa = user.forLLM('openai', { integrationId: 'hubspot' });

const completion = await openai.chat.completions.create({
  model: 'gpt-5.2',
  messages,
  tools: await oa.tools(),                       // ChatCompletionTool[]
});

const toolMessages = await oa.run(completion.choices[0].message.tool_calls ?? []);
// role:'tool' messages, ready to append and continue the conversation

Curate what the model sees

Don't hand a model 85 tools when the task needs 4. Two levers:

  • Filter by integration at the adapter ({ integrationId: 'gmail' }), as above.
  • Curate a toolset — a named, workspace-level selection with renames and per-tool policies — and serve that instead. Toolsets are how you keep one vocabulary across chat, MCP, and automations; see White-label and Per-user MCP sessions.

When a call can't run

Execution results carry structured failure information — the three you should design UI for:

ResultMeaningYour move
authRequired / not connectedThe user's credential is missing or expiredShow reconnect (recipe)
pendingApproval + approvalIdA policy gated the call for human sign-offRoute to your approval inbox (recipe)
error with retryAfterProvider rate limitBack off and retry — the SDK never retries for you

Production notes

  • Tokens never reach the model. The adapter sends tool calls to Protobox; the provider credential is applied server-side. Prompt-injected exfiltration of a token is structurally impossible.
  • Per-request identity: everything on user.… executes as that entity. For multi-account users, scope with user.account('work').forLLM(…).
  • Latency: each run() is one round-trip per tool-call to the platform, which calls the provider. Batch-friendly models (parallel tool use) work — run() executes every call in the message.

On this page