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-sideFive 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 conversationCurate 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:
| Result | Meaning | Your move |
|---|---|---|
authRequired / not connected | The user's credential is missing or expired | Show reconnect (recipe) |
pendingApproval + approvalId | A policy gated the call for human sign-off | Route to your approval inbox (recipe) |
error with retryAfter | Provider rate limit | Back 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 withuser.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.
Related
- Framework adapters reference
- Automations — the same execution path, without a conversation
Connect your users' apps
Add a "Connect Gmail" button to your product — hosted OAuth per end-user, managed token refresh, multi-account, and clean offboarding.
Your API as agent tools
Register your own OpenAPI spec — or a code bundle — as a private connector, and your product's actions become first-class agent tools beside the catalog.