Framework Adapters
Hand integration tools to OpenAI, Anthropic, or the Vercel AI SDK in one line.
An adapter converts an integration's tools into a provider's tool-calling format and runs the model's tool-calls back through the platform. Get one with forLLM(provider, options) — on the SDK, or on an entity to scope execution to a user.
const gh = protobox.entity('user_123').forLLM('anthropic', { integrationId: 'github' });Every adapter exposes .tools() (fetch the provider-formatted tools) and a run method that executes the model's tool-calls and returns provider-shaped results.
Anthropic
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic();
const gh = user.forLLM('anthropic', { integrationId: 'github' });
const tools = await gh.tools(); // [{ name, description, input_schema }]
let message = await anthropic.messages.create({
model: 'claude-sonnet-5',
max_tokens: 1024,
tools,
messages,
});
// Execute any tool_use blocks and feed the results back
const toolResults = await gh.run(message.content); // [{ type: 'tool_result', tool_use_id, content }]
messages.push({ role: 'assistant', content: message.content });
messages.push({ role: 'user', content: toolResults });OpenAI
import OpenAI from 'openai';
const openai = new OpenAI();
const gh = user.forLLM('openai', { integrationId: 'github' });
const tools = await gh.tools(); // ChatCompletionTool[]
const res = await openai.chat.completions.create({ model: 'gpt-4o', messages, tools });
const toolMessages = await gh.run(res.choices[0].message.tool_calls ?? []);
// toolMessages are role:'tool' messages — append them and continue the loop
messages.push(res.choices[0].message, ...toolMessages);Vercel AI SDK
import { generateText } from 'ai';
const gh = user.forLLM('vercel', { integrationId: 'github' });
const tools = await gh.tools(); // { [name]: { description, parameters, inputSchema, execute } }
const { text } = await generateText({ model, prompt, tools, maxSteps: 5 });The Vercel tool set includes both parameters (AI SDK v4) and inputSchema (AI SDK v5), each holding the tool's JSON Schema. If your AI SDK version validates the schema type, wrap it with jsonSchema() from the ai package:
tool({ description: t.description, inputSchema: jsonSchema(t.inputSchema), execute: t.execute }).
Error handling inside the loop
Adapter run methods never throw for tool-level failures — they encode the error in the provider's result shape so the model can react:
- OpenAI / Anthropic — the tool message/
tool_resultcontent is{ "error": "..." }(Anthropic also setsis_error: true). - Vercel —
executeresolves to{ error: "..." }.
For connection problems specifically, a direct execute() call exposes result.authRequired — see Managed auth.