Frameworks
Give a session's tools to your agent framework or model API, in its own format.
Pick a provider when you create the client. session.tools() then returns tools in that
framework's own type, ready to pass in. No casts.
const dexby = new Dexby({ provider: new AiSdkProvider() })
const tools = await dexby
.createSession({ userId: 'user_123', connectors: ['slack'] })
.andThen((session) => session.tools())
if (tools.isErr()) throw new Error(tools.error.message)
// tools.value is an AI SDK ToolSetAgent frameworks
The framework calls each tool through Dexby with the user's connected accounts. Install the
framework next to @dexby.ai/sdk. Allow several steps: the model searches for a tool before it runs it.
import { openai } from '@ai-sdk/openai'
import { Dexby } from '@dexby.ai/sdk'
import { AiSdkProvider } from '@dexby.ai/sdk/providers/ai-sdk'
import { generateText, stepCountIs } from 'ai'
const dexby = new Dexby({ userId: 'user_123', provider: new AiSdkProvider() })
const tools = await dexby.createSession({ connectors: ['slack'] }).andThen((s) => s.tools())
if (tools.isErr()) throw new Error(tools.error.message)
const { text } = await generateText({
model: openai('gpt-5'),
tools: tools.value,
stopWhen: stepCountIs(8),
prompt: 'Post "Deploy finished" to #general'
})Frameworks that take AI SDK tools, such as Cloudflare's Agents SDK, use AiSdkProvider.
Model APIs
These providers return plain tool definitions without a framework dependency. Install the model
client package used by your application. Your code runs each tool call with
session.call(name, input) and sends the result back.
The snippets below show only tool dispatch. The comments mark where your application must send results back to the model and continue the loop; these are not complete agent runs.
import Anthropic from '@anthropic-ai/sdk'
import { Dexby } from '@dexby.ai/sdk'
import { AnthropicProvider } from '@dexby.ai/sdk/providers/anthropic'
const anthropic = new Anthropic()
const dexby = new Dexby({ userId: 'user_123', provider: new AnthropicProvider() })
const created = await dexby.createSession({ connectors: ['slack'] })
if (created.isErr()) throw new Error(created.error.message)
const session = created.value
const tools = await session.tools()
if (tools.isErr()) throw new Error(tools.error.message)
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
tools: tools.value,
messages: [{ role: 'user', content: 'Post "Deploy finished" to #general' }]
})
for (const block of message.content) {
if (block.type !== 'tool_use') continue
const outcome = await session.call(block.name, block.input)
if (outcome.isErr()) throw new Error(outcome.error.message)
// Send back { type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(outcome.value) }
}Good to know
- A tool returns
{ ok: true, result }or{ ok: false, error }. The model reads both. A refusal, such as an app that is not connected, is not an exception. See Errors. - Stopping a run cancels the Dexby call, except in LlamaIndex (no abort signal for tools) and Genkit's
generate(does not pass its signal to tools). - Mastra, LangChain and Genkit check tool input against the schema first. Mastra hands a mismatch back to the model; LangChain and Genkit throw.
- Each framework is an optional dependency, loaded only by its own provider import.
- Another format? Implement
ToolProviderfrom@dexby.ai/sdk/contracts. See the SDK reference.